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); }
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"); } }
/// <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()); } }
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); } }
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); } }
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); } }
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); } }
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); } }
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)); }
/// <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); }
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; } } }
/// <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)); }
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); }