public static MessageObject CreateNewMessage(PSTFile file, FolderItemTypeName folderItemType, NodeID parentNodeID, Guid searchKey)
        {
            // [MS-PST] The following properties must be present in any valid Message object PC:
            PropertyContext pc = PropertyContext.CreateNewPropertyContext(file);

            pc.SetStringProperty(PropertyID.PidTagMessageClass, GetMessageClass(folderItemType));

            pc.SetInt32Property(PropertyID.PidTagMessageFlags, 0);
            pc.SetInt32Property(PropertyID.PidTagMessageStatus, 0);
            pc.SetDateTimeProperty(PropertyID.PidTagCreationTime, DateTime.UtcNow);
            pc.SetDateTimeProperty(PropertyID.PidTagLastModificationTime, DateTime.UtcNow);
            pc.SetDateTimeProperty(PropertyID.PidTagClientSubmitTime, DateTime.UtcNow);
            pc.SetDateTimeProperty(PropertyID.PidTagMessageDeliveryTime, DateTime.UtcNow);
            byte[] conversationIndex = ConversationIndexHeader.GenerateNewConversationIndex().GetBytes();
            pc.SetBytesProperty(PropertyID.PidTagConversationIndex, conversationIndex);

            // PidTagSearchKey is apparently a GUID
            pc.SetBytesProperty(PropertyID.PidTagSearchKey, LittleEndianConverter.GetBytes(searchKey));

            pc.SaveChanges();

            NodeID pcNodeID = file.Header.AllocateNextNodeID(NodeTypeName.NID_TYPE_NORMAL_MESSAGE);

            file.NodeBTree.InsertNodeEntry(pcNodeID, pc.DataTree, pc.SubnodeBTree, parentNodeID);

            // NOTE: According to [MS-PST], A Recipient Table MUST exist for any Message object,
            //       However, in practice even outlook itself does not always create it.
            PSTNode       pcNode  = new PSTNode(file, pcNodeID, pc.DataTree, pc.SubnodeBTree);
            MessageObject message = new MessageObject(pcNode);

            return(message);
        }
Beispiel #2
0
        public static PSTFolder GetFolder(PSTNode node)
        {
            if (node.NodeID.nidType == NodeTypeName.NID_TYPE_NORMAL_FOLDER)
            {
                PropertyContext pc = node.PC;
                if (pc != null)
                {
                    string             containerClass = pc.GetStringProperty(PropertyID.PidTagContainerClass);
                    FolderItemTypeName itemType       = GetItemType(containerClass);
                    switch (itemType)
                    {
                    case FolderItemTypeName.Appointment:
                        return(new CalendarFolder(node));

                    case FolderItemTypeName.Note:
                        return(new MailFolder(node));

                    default:
                        return(new PSTFolder(node));
                    }
                }
                else
                {
                    throw new Exception("PC is null");
                }
            }
            else
            {
                throw new Exception("Node ID does not belong to a folder");
            }
        }
Beispiel #3
0
        /// <summary>
        /// Dissociate child folder from this (parent) folder, changes will be saved immediately
        /// </summary>
        public void RemoveChildFolder(PSTFolder childFolder)
        {
            TableContext hierarchyTable = GetHierarchyTable();
            int          rowIndex       = hierarchyTable.GetRowIndex(childFolder.NodeID.Value);

            if (rowIndex >= 0)
            {
                if (this.ChildFolderCount == 1)
                {
                    PropertyContext pc = this.PC;
                    pc.SetBooleanProperty(PropertyID.PidTagSubfolders, false);
                    pc.SaveChanges(NodeID);

                    // update hierarchy table of parent (set PidTagSubfolders of current folder to false):
                    TableContext parentHierarchyTable = ParentFolder.GetHierarchyTable();
                    int          rowIndexOfFolder     = parentHierarchyTable.GetRowIndex(NodeID.Value);
                    parentHierarchyTable.SetBooleanProperty(rowIndexOfFolder, PropertyID.PidTagSubfolders, false);
                    parentHierarchyTable.SaveChanges(ParentFolder.GetHierarchyTableNodeID());
                }

                hierarchyTable.DeleteRow(rowIndex);

                hierarchyTable.SaveChanges(GetHierarchyTableNodeID());
            }
        }
Beispiel #4
0
 public static void CopyBytesProperty(PropertyContext pc, TableContext tc, int rowIndex, PropertyID propertyID)
 {
     byte[] value = pc.GetBytesProperty(propertyID);
     if (value != null && tc.ContainsPropertyColumn(propertyID, PropertyTypeName.PtypBinary))
     {
         tc.SetBytesProperty(rowIndex, propertyID, value);
     }
 }
Beispiel #5
0
        public static void CopyInt64Property(PropertyContext pc, TableContext tc, int rowIndex, PropertyID propertyID)
        {
            Nullable <long> value = pc.GetInt64Property(propertyID);

            if (value.HasValue && tc.ContainsPropertyColumn(propertyID, PropertyTypeName.PtypInteger64))
            {
                tc.SetInt64Property(rowIndex, propertyID, value.Value);
            }
        }
Beispiel #6
0
        public static void CopyBooleanProperty(PropertyContext pc, TableContext tc, int rowIndex, PropertyID propertyID)
        {
            Nullable <bool> value = pc.GetBooleanProperty(propertyID);

            if (value.HasValue && tc.ContainsPropertyColumn(propertyID, PropertyTypeName.PtypBoolean))
            {
                tc.SetBooleanProperty(rowIndex, propertyID, value.Value);
            }
        }
Beispiel #7
0
        public static void CopyStringProperty(PropertyContext pc, TableContext tc, int rowIndex, PropertyID propertyID)
        {
            string value = pc.GetStringProperty(propertyID);

            if (value != null && tc.ContainsPropertyColumn(propertyID, PropertyTypeName.PtypString))
            {
                tc.SetStringProperty(rowIndex, propertyID, value);
            }
        }
Beispiel #8
0
        public static void CopyDateTimeProperty(PropertyContext pc, TableContext tc, int rowIndex, PropertyID propertyID)
        {
            Nullable <DateTime> value = pc.GetDateTimeProperty(propertyID);

            if (value.HasValue && tc.ContainsPropertyColumn(propertyID, PropertyTypeName.PtypTime))
            {
                tc.SetDateTimeProperty(rowIndex, propertyID, value.Value);
            }
        }
Beispiel #9
0
        public static AttachmentObject CreateNewAttachmentObject(PSTFile file, SubnodeBTree subnodeBTree)
        {
            PropertyContext pc = PropertyContext.CreateNewPropertyContext(file);

            pc.SaveChanges();

            NodeID pcNodeID = file.Header.AllocateNextNodeID(NodeTypeName.NID_TYPE_ATTACHMENT);

            subnodeBTree.InsertSubnodeEntry(pcNodeID, pc.DataTree, pc.SubnodeBTree);

            Subnode subnode = new Subnode(file, pcNodeID, pc.DataTree, pc.SubnodeBTree);

            return(new AttachmentObject(subnode));
        }
Beispiel #10
0
        /// <summary>
        /// Changes will be saved immediately
        /// </summary>
        public PSTFolder CreateChildFolder(string folderName, FolderItemTypeName folderItemType)
        {
            PSTFolder       childFolder = CreateNewFolder(this.File, folderName, folderItemType, this.NodeID);
            PropertyContext pc          = this.PC;

            if (!pc.GetBooleanProperty(PropertyID.PidTagSubfolders).Value)
            {
                pc.SetBooleanProperty(PropertyID.PidTagSubfolders, true);
                pc.SaveChanges(NodeID);
            }
            // update hierarchy table of parent (set PidTagSubfolders of current folder to true):
            TableContext parentHierarchyTable = ParentFolder.GetHierarchyTable();
            int          rowIndexOfFolder     = parentHierarchyTable.GetRowIndex(NodeID.Value);

            if (!parentHierarchyTable.GetBooleanProperty(rowIndexOfFolder, PropertyID.PidTagSubfolders).Value)
            {
                parentHierarchyTable.SetBooleanProperty(rowIndexOfFolder, PropertyID.PidTagSubfolders, true);
                parentHierarchyTable.SaveChanges(ParentFolder.GetHierarchyTableNodeID());
            }

            // update hierarchy table:
            TableContext hierarchyTable = GetHierarchyTable();

            hierarchyTable.AddRow(childFolder.NodeID.Value);
            int rowIndex = hierarchyTable.RowCount - 1;

            // Template properties (assured to be present)
            hierarchyTable.SetInt32Property(rowIndex, PropertyID.PidTagContentCount, 0);
            hierarchyTable.SetInt32Property(rowIndex, PropertyID.PidTagContentUnreadCount, 0);
            hierarchyTable.SetBooleanProperty(rowIndex, PropertyID.PidTagSubfolders, false);
            hierarchyTable.SetStringProperty(rowIndex, PropertyID.PidTagDisplayName, folderName);
            hierarchyTable.SetStringProperty(rowIndex, PropertyID.PidTagContainerClass, GetContainerClass(folderItemType));
            hierarchyTable.SetInt32Property(rowIndex, PropertyID.PidTagLtpRowId, (int)childFolder.NodeID.Value);
            // PidTagLtpRowVer uses dwUnique
            int rowVersion = (int)File.Header.AllocateNextUniqueID();

            hierarchyTable.SetInt32Property(rowIndex, PropertyID.PidTagLtpRowVer, rowVersion);

            hierarchyTable.SaveChanges(GetHierarchyTableNodeID());

            this.File.SearchManagementQueue.AddFolder(childFolder.NodeID, this.NodeID);

            return(childFolder);
        }
Beispiel #11
0
        public static void CopyProperties(PropertyContext pc, TableContext tc, int rowIndex)
        {
            // Note: Outlook 2003 simply iterates over all of the table columns:
            foreach (TableColumnDescriptor descriptor in tc.Columns)
            {
                switch (descriptor.PropertyType)
                {
                case PropertyTypeName.PtypBoolean:
                    CopyBooleanProperty(pc, tc, rowIndex, descriptor.PropertyID);
                    break;

                case PropertyTypeName.PtypInteger16:
                    CopyInt16Property(pc, tc, rowIndex, descriptor.PropertyID);
                    break;

                case PropertyTypeName.PtypInteger32:
                    CopyInt32Property(pc, tc, rowIndex, descriptor.PropertyID);
                    break;

                case PropertyTypeName.PtypInteger64:
                    CopyInt64Property(pc, tc, rowIndex, descriptor.PropertyID);
                    break;

                case PropertyTypeName.PtypTime:
                    CopyDateTimeProperty(pc, tc, rowIndex, descriptor.PropertyID);
                    break;

                case PropertyTypeName.PtypGuid:
                    CopyGuidProperty(pc, tc, rowIndex, descriptor.PropertyID);
                    break;

                case PropertyTypeName.PtypBinary:
                    CopyBytesProperty(pc, tc, rowIndex, descriptor.PropertyID);
                    break;

                case PropertyTypeName.PtypString:
                    CopyStringProperty(pc, tc, rowIndex, descriptor.PropertyID);
                    break;

                default:
                    break;
                }
            }
        }
Beispiel #12
0
        /// <summary>
        /// Caller must update its hierarchy table to include the new child
        /// </summary>
        public static PSTFolder CreateNewFolder(PSTFile file, string folderName, FolderItemTypeName folderItemType, NodeID parentNodeID)
        {
            // create the normal folder node
            PropertyContext pc = PropertyContext.CreateNewPropertyContext(file);

            pc.SetStringProperty(PropertyID.PidTagDisplayName, folderName);
            pc.SetInt32Property(PropertyID.PidTagContentCount, 0);
            pc.SetInt32Property(PropertyID.PidTagContentUnreadCount, 0);
            pc.SetBooleanProperty(PropertyID.PidTagSubfolders, false);
            pc.SetStringProperty(PropertyID.PidTagContainerClass, GetContainerClass(folderItemType));
            pc.SaveChanges();

            NodeID pcNodeID = file.Header.AllocateNextFolderNodeID();

            file.NodeBTree.InsertNodeEntry(pcNodeID, pc.DataTree, pc.SubnodeBTree, parentNodeID);
            PSTNode pcNode = new PSTNode(file, pcNodeID, pc.DataTree, pc.SubnodeBTree);

            // There is no need to create a new empty TC, we can simply point to the appropriate template
            // and only update the reference to another data tree during modification
            PSTNode hierarchyTableTemplateNode = file.GetNode(InternalNodeName.NID_HIERARCHY_TABLE_TEMPLATE);
            NodeID  hierarchyTableNodeID       = new NodeID(NodeTypeName.NID_TYPE_HIERARCHY_TABLE, pcNodeID.nidIndex);

            file.NodeBTree.InsertNodeEntry(hierarchyTableNodeID, hierarchyTableTemplateNode.DataTree, null, new NodeID(0));
            file.BlockBTree.IncrementBlockEntryReferenceCount(hierarchyTableTemplateNode.DataTree.RootBlock.BlockID);

            PSTNode contentsTableTemplateNode = file.GetNode(InternalNodeName.NID_CONTENTS_TABLE_TEMPLATE);
            NodeID  contentsTableNodeID       = new NodeID(NodeTypeName.NID_TYPE_CONTENTS_TABLE, pcNodeID.nidIndex);

            file.NodeBTree.InsertNodeEntry(contentsTableNodeID, contentsTableTemplateNode.DataTree, null, new NodeID(0));
            file.BlockBTree.IncrementBlockEntryReferenceCount(contentsTableTemplateNode.DataTree.RootBlock.BlockID);

            PSTNode associatedContentsTableTemplateNode = file.GetNode(InternalNodeName.NID_ASSOC_CONTENTS_TABLE_TEMPLATE);
            NodeID  associatedContentsTableNodeID       = new NodeID(NodeTypeName.NID_TYPE_ASSOC_CONTENTS_TABLE, pcNodeID.nidIndex);

            file.NodeBTree.InsertNodeEntry(associatedContentsTableNodeID, associatedContentsTableTemplateNode.DataTree, null, new NodeID(0));
            file.BlockBTree.IncrementBlockEntryReferenceCount(associatedContentsTableTemplateNode.DataTree.RootBlock.BlockID);

            PSTFolder folder = PSTFolder.GetFolder(pcNode);

            return(folder);
        }
        public static ModifiedAppointmentInstance CreateNewModifiedInstance(PSTFile file, SubnodeBTree attachmentSubnodeBTree)
        {
            PropertyContext pc = PropertyContext.CreateNewPropertyContext(file);

            pc.SetStringProperty(PropertyID.PidTagMessageClass, RecurringAppointmentExceptionMessageClass);
            pc.SetDateTimeProperty(PropertyID.PidTagCreationTime, DateTime.UtcNow);
            pc.SetDateTimeProperty(PropertyID.PidTagLastModificationTime, DateTime.UtcNow);

            // PidTagSearchKey is apparently a GUID
            pc.SetBytesProperty(PropertyID.PidTagSearchKey, LittleEndianConverter.GetBytes(Guid.NewGuid()));

            pc.SaveChanges();

            NodeID subnodeID = file.Header.AllocateNextNodeID(NodeTypeName.NID_TYPE_NORMAL_MESSAGE);

            attachmentSubnodeBTree.InsertSubnodeEntry(subnodeID, pc.DataTree, pc.SubnodeBTree);

            Subnode subnode = new Subnode(file, subnodeID, pc.DataTree, pc.SubnodeBTree);

            return(new ModifiedAppointmentInstance(subnode));
        }
Beispiel #14
0
 public NamedPropertyContext(PropertyContext pc, PropertyNameToIDMap map) : base(pc.Heap, pc.SubnodeBTree)
 {
     m_map = map;
 }
        /// <summary>
        /// For discovery purposes
        /// </summary>
        public List <string> ListAllProperties()
        {
            List <string> result = new List <string>();
            List <PropertyContextRecord> properties = GetAllProperties();

            foreach (PropertyContextRecord record in properties)
            {
                string value;
                switch (record.wPropType)
                {
                case PropertyTypeName.PtypBoolean:
                    value = GetBooleanProperty(record.wPropId).ToString();
                    break;

                case PropertyTypeName.PtypInteger16:
                    value = GetInt16Property(record.wPropId).ToString() + " (Int16)";
                    break;

                case PropertyTypeName.PtypInteger32:
                    value = GetInt32Property(record.wPropId).ToString();
                    break;

                case PropertyTypeName.PtypInteger64:
                    value = GetInt64Property(record.wPropId).ToString() + " (Int64)";
                    break;

                case PropertyTypeName.PtypFloating32:
                    value = GetFloat32Property(record.wPropId).ToString() + " (Float32)";
                    break;

                case PropertyTypeName.PtypFloating64:
                    value = GetFloat64Property(record.wPropId).ToString() + " (Float64)";
                    break;

                case PropertyTypeName.PtypTime:
                    value = GetDateTimeProperty(record.wPropId).ToString();
                    break;

                case PropertyTypeName.PtypString:
                    value = GetStringProperty(record.wPropId);
                    break;

                case PropertyTypeName.PtypMultiString:
                    value = "Unsupported type: MultiString";
                    break;

                case PropertyTypeName.PtypBinary:
                {
                    try
                    {
                        byte[] bytes = GetBytesProperty((PropertyID)record.wPropId);
                        value = StringHelper.GetByteArrayString(bytes);
                    }
                    catch (MissingSubnodeException)
                    {
                        value = "Missing (Binary)";
                    }
                    break;
                }

                case PropertyTypeName.PtypObject:
                {
                    PropertyContext pc = GetObjectProperty((PropertyID)record.wPropId).PC;
                    value = "Subnode PC:\r\n";
                    if (pc != null)
                    {
                        List <string> subProperies = pc.ListAllProperties();
                        foreach (string line in subProperies)
                        {
                            value += "\t" + line + "\r\n";
                        }
                    }
                    break;
                }

                default:
                    value = "unknown type: 0x" + record.wPropType.ToString("x");
                    break;
                }

                string propertyIDString = GetPropertyIDString((ushort)record.wPropId);
                result.Add(propertyIDString + ": " + value);
            }

            return(result);
        }