private void UpdateAttachment(PSTFile file, AttachmentObject attachment) { int rowIndex = GetRowIndex(attachment.SubnodeID.Value); if (rowIndex >= 0) { UpdateAttachment(file, attachment, rowIndex); } }
/// <param name="subnodeBTree">Note: We use ref, this way we are able to create a new subnode BTree and update the subnodeBTree the caller provided</param> /// <param name="heapOrNodeID">Existing HeapOrNodeID</param> public static HeapOrNodeID StoreExternalProperty(PSTFile file, HeapOnNode heap, ref SubnodeBTree subnodeBTree, HeapOrNodeID heapOrNodeID, byte[] propertyBytes) { // We should avoid storing items with length of 0, because those are consideref freed, and could be repurposed if (propertyBytes.Length == 0) { RemoveExternalProperty(heap, subnodeBTree, heapOrNodeID); return(new HeapOrNodeID(HeapID.EmptyHeapID)); } if (heapOrNodeID.IsHeapID) // if HeapOrNodeID is empty then IsHeapID == true { if (propertyBytes.Length <= HeapOnNode.MaximumAllocationLength) { if (heapOrNodeID.IsEmpty) { return(new HeapOrNodeID(heap.AddItemToHeap(propertyBytes))); } else { return(new HeapOrNodeID(heap.ReplaceHeapItem(heapOrNodeID.HeapID, propertyBytes))); } } else // old data (if exist) is stored on heap, but new data needs a subnode { if (!heapOrNodeID.IsEmpty) { heap.RemoveItemFromHeap(heapOrNodeID.HeapID); } if (subnodeBTree == null) { subnodeBTree = new SubnodeBTree(file); } DataTree dataTree = new DataTree(file); dataTree.AppendData(propertyBytes); dataTree.SaveChanges(); NodeID subnodeID = file.Header.AllocateNextNodeID(NodeTypeName.NID_TYPE_LTP); subnodeBTree.InsertSubnodeEntry(subnodeID, dataTree, null); return(new HeapOrNodeID(subnodeID)); } } else // old data is stored in a subnode { Subnode subnode = subnodeBTree.GetSubnode(heapOrNodeID.NodeID); if (subnode.DataTree != null) { subnode.DataTree.Delete(); } subnode.DataTree = new DataTree(subnodeBTree.File); subnode.DataTree.AppendData(propertyBytes); subnode.SaveChanges(subnodeBTree); return(new HeapOrNodeID(heapOrNodeID.NodeID)); } }
public static FreeMapPage ReadFreeMapPage(PSTFile file, int fMapPageIndex) { long offset = FirstPageOffset + (long)MapppedLength * fMapPageIndex; file.BaseStream.Seek(offset, SeekOrigin.Begin); byte[] buffer = new byte[Length]; file.BaseStream.Read(buffer, 0, Length); return(new FreeMapPage(buffer)); }
public static HeapOnNode CreateNewHeap(PSTFile file) { DataTree dataTree = new DataTree(file); HeapOnNodeFirstBlockData blockData = new HeapOnNodeFirstBlockData(); dataTree.UpdateDataBlock(0, blockData.GetBytes()); // now the data tree contains a valid HN HeapOnNode heap = new HeapOnNode(dataTree); return(heap); }
public static AllocationMapPage ReadAllocationMapPage(PSTFile file, int allocationMapPageIndex) { // The first AMap of a PST file is always located at absolute file offset 0x4400, and subsequent AMaps appear at intervals of 253,952 bytes thereafter long offset = FirstPageOffset + (long)MapppedLength * allocationMapPageIndex; file.BaseStream.Seek(offset, SeekOrigin.Begin); byte[] buffer = new byte[Length]; file.BaseStream.Read(buffer, 0, Length); return(new AllocationMapPage(buffer)); }
public static Note GetNote(PSTFile file, NodeID nodeID) { PSTNode node = file.GetNode(nodeID); NamedPropertyContext pc = node.PC; if (pc != null) { return(new Note(node)); } else { return(null); } }
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)); }
public static Note CreateNewNote(PSTFile file, NodeID parentNodeID, Guid searchKey) { MessageObject message = CreateNewMessage(file, FolderItemTypeName.Note, parentNodeID, searchKey); Note note = new Note(message); note.MessageFlags = MessageFlags.MSGFLAG_READ; note.InternetCodepage = 1255; note.MessageDeliveryTime = DateTime.UtcNow; note.ClientSubmitTime = DateTime.UtcNow; note.SideEffects = SideEffectsFlags.seOpenForCtxMenu | SideEffectsFlags.seOpenToMove | SideEffectsFlags.seOpenToCopy | SideEffectsFlags.seCoerceToInbox | SideEffectsFlags.seOpenToDelete; note.Importance = MessageImportance.Normal; note.Priority = MessagePriority.Normal; note.IconIndex = IconIndex.NewMail; return(note); }
public static RecurringAppointment CreateNewRecurringAppointment(PSTFile file, NodeID parentNodeID, Guid searchKey) { MessageObject message = CreateNewMessage(file, FolderItemTypeName.Appointment, parentNodeID, searchKey); RecurringAppointment appointment = new RecurringAppointment(message); appointment.MessageFlags = MessageFlags.MSGFLAG_READ; appointment.InternetCodepage = 1255; appointment.MessageDeliveryTime = DateTime.UtcNow; appointment.ClientSubmitTime = DateTime.UtcNow; appointment.SideEffects = SideEffectsFlags.seOpenForCtxMenu | SideEffectsFlags.seOpenToMove | SideEffectsFlags.seOpenToCopy | SideEffectsFlags.seCoerceToInbox | SideEffectsFlags.seOpenToDelete; appointment.Importance = MessageImportance.Normal; appointment.Priority = MessagePriority.Normal; appointment.ConferencingType = MeetingType.WindowsNetmeeting; appointment.IconIndex = IconIndex.RecurringAppointment; return(appointment); }
private static void UpdateFMap(PSTFile file, AllocationMapPage targetPage, int targetPageIndex) { byte fMax = (byte)Math.Min(255, targetPage.GetMaxContiguousSpace() / 64); int fmapPageIndex = FreeMapPage.GetFreeMapPageIndex(targetPageIndex); int fmapPageEntryIndex = FreeMapPage.GetFreeMapEntryIndex(targetPageIndex); if (fmapPageIndex >= 0) { FreeMapPage fmap = FreeMapPage.ReadFreeMapPage(file, fmapPageIndex); fmap.rgbFMapBits[fmapPageEntryIndex] = fMax; fmap.WriteFreeMapPage(file, fmapPageIndex); } else { file.Header.rgbFM[fmapPageEntryIndex] = fMax; } }
public static WriterCompatibilityMode AutoDetectPSTWriter(PSTFile file) { if (file.Header.root.fAMapValid > 0) { if (file.Header.root.fAMapValid == RootStructure.VALID_AMAP1) { return(WriterCompatibilityMode.Outlook2003RTM); } else if (file.Header.root.fAMapValid == RootStructure.VALID_AMAP2) { return(WriterCompatibilityMode.Outlook2007RTM); // check if DList exist } } // default to Outlook2003 return(WriterCompatibilityMode.Outlook2003RTM); }
/// <returns>Offset of space allocated</returns> private static long AllocateSpace(PSTFile file, int allocationLength, bool pageAligned) { if (allocationLength > MaxAllocationLength) { throw new Exception("Invalid allocation length requested"); } int numberOfPages = file.Header.root.NumberOfAllocationMapPages; AllocationMapPage targetPage = null; int targetPageIndex = 0; for (int index = 0; index < numberOfPages; index++) { AllocationMapPage page = AllocationMapPage.ReadAllocationMapPage(file, index); int startOffset = page.FindContiguousSpace(allocationLength, pageAligned); if (startOffset > 0) // 0 is allocated to the AMAP itself and is not a valid value { targetPage = page; targetPageIndex = index; break; } } if (targetPage == null) { // no space was found within existing pages targetPageIndex = numberOfPages; targetPage = GrowPST(file, targetPageIndex); } int targetPageStartOffset = targetPage.FindContiguousSpace(allocationLength, pageAligned); targetPage.AllocateSpace(targetPageStartOffset, allocationLength); targetPage.WriteAllocationMapPage(file, targetPageIndex); UpdateFMap(file, targetPage, targetPageIndex); file.Header.root.cbAMapFree -= (uint)allocationLength; //InvalidatePMap(file); //InvalidateDList(file); return(AllocationMapPage.FirstPageOffset + (long)targetPageIndex * AllocationMapPage.MapppedLength + targetPageStartOffset); }
public static PSTFolder GetFolder(PSTFile file, NodeID nodeID) { if (nodeID.nidType == NodeTypeName.NID_TYPE_NORMAL_FOLDER) { PSTNode node = file.GetNode(nodeID); if (node != null) { return(GetFolder(node)); } else { return(null); } } else { throw new Exception("Node ID does not belong to a folder"); } }
/// <param name="subnodeBTree">Subnode BTree that will be associated with the new PC</param> public static PropertyContext CreateNewPropertyContext(PSTFile file, SubnodeBTree subnodeBTree) { HeapOnNode heap = HeapOnNode.CreateNewHeap(file); BTreeOnHeapHeader bTreeHeader = new BTreeOnHeapHeader(); bTreeHeader.cbKey = PropertyContextRecord.RecordKeyLength; bTreeHeader.cbEnt = PropertyContextRecord.RecordDataLength; HeapID newUserRoot = heap.AddItemToHeap(bTreeHeader.GetBytes()); // The heap header may have just been updated HeapOnNodeHeader header = heap.HeapHeader; header.bClientSig = OnHeapTypeName.bTypePC; header.hidUserRoot = newUserRoot; heap.UpdateHeapHeader(header); heap.FlushToDataTree(); return(new PropertyContext(heap, subnodeBTree)); }
/// <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 AttachmentObject CreateNewExceptionAttachmentObject(PSTFile file, SubnodeBTree subnodeBTree) { AttachmentObject attachment = CreateNewAttachmentObject(file, subnodeBTree); attachment.PC.SetStringProperty(PropertyID.PidTagDisplayName, "Untitled"); attachment.PC.SetStringProperty(PropertyID.PidTagAttachEncoding, String.Empty); //attachment.PC.SetBytesProperty(PropertyID.PidTagAttachRendering, AppointmentAttachRendering); attachment.PC.SetInt32Property(PropertyID.PidTagAttachMethod, (int)AttachMethod.EmbeddedMessage); attachment.PC.SetInt32Property(PropertyID.PidTagAttachFlags, 0); attachment.PC.SetInt32Property(PropertyID.PidTagAttachmentFlags, (int)AttachmentFlags.afException); attachment.PC.SetInt32Property(PropertyID.PidTagAttachmentLinkId, 0); attachment.PC.SetInt32Property(PropertyID.PidTagRenderingPosition, -1); attachment.PC.SetBooleanProperty(PropertyID.PidTagAttachmentHidden, true); attachment.PC.SetBooleanProperty(PropertyID.PidTagAttachmentContactPhoto, false); attachment.CreateSubnodeBTreeIfNotExist(); return(attachment); }
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 static Appointment GetAppointment(PSTFile file, NodeID nodeID) { PSTNode node = file.GetNode(nodeID); NamedPropertyContext pc = node.PC; if (pc != null) { bool recurring = pc.GetBooleanProperty(PropertyNames.PidLidRecurring, false); if (recurring) { return(new RecurringAppointment(node)); } else { return(new SingleAppointment(node)); } } else { return(null); } }
private void AddAttachmentTableColumns(PSTFile file) { this.AddPropertyColumnIfNotExist(PropertyID.PidTagDisplayName, PropertyTypeName.PtypString); this.AddPropertyColumnIfNotExist(PropertyID.PidTagAttachExtension, PropertyTypeName.PtypString); this.AddPropertyColumnIfNotExist(PropertyID.PidTagAttachLongFilename, PropertyTypeName.PtypString); this.AddPropertyColumnIfNotExist(PropertyID.PidTagAttachPathname, PropertyTypeName.PtypString); this.AddPropertyColumnIfNotExist(PropertyID.PidTagAttachTag, PropertyTypeName.PtypBinary); this.AddPropertyColumnIfNotExist(PropertyID.PidTagAttachLongPathname, PropertyTypeName.PtypString); this.AddPropertyColumnIfNotExist(PropertyID.PidTagAttachMimeTag, PropertyTypeName.PtypString); this.AddPropertyColumnIfNotExist(PropertyID.PidTagAttachAdditionalInformation, PropertyTypeName.PtypBinary); this.AddPropertyColumnIfNotExist(PropertyID.PidTagAttachContentBase, PropertyTypeName.PtypString); this.AddPropertyColumnIfNotExist(PropertyID.PidTagAttachContentId, PropertyTypeName.PtypString); this.AddPropertyColumnIfNotExist(PropertyID.PidTagAttachContentLocation, PropertyTypeName.PtypString); //this.AddPropertyColumnIfNotExist(PropertyID.Unknown0x6909, PropertyTypeName.PtypInteger32); this.AddPropertyColumnIfNotExist(PropertyID.PidTagAttachmentLinkId, PropertyTypeName.PtypInteger32); this.AddPropertyColumnIfNotExist(PropertyID.PidTagExceptionStartTime, PropertyTypeName.PtypTime); this.AddPropertyColumnIfNotExist(PropertyID.PidTagExceptionEndTime, PropertyTypeName.PtypTime); this.AddPropertyColumnIfNotExist(PropertyID.PidTagAttachmentFlags, PropertyTypeName.PtypInteger32); this.AddPropertyColumnIfNotExist(PropertyID.PidTagAttachmentHidden, PropertyTypeName.PtypBoolean); this.AddPropertyColumnIfNotExist(PropertyID.PidTagExceptionReplaceTime, PropertyTypeName.PtypTime); this.AddPropertyColumnIfNotExist(PropertyID.PidTagAttachmentContactPhoto, PropertyTypeName.PtypBoolean); }
public void AddRecipient(PSTFile file, MessageRecipient recipient) { AddRecipient(file, recipient.DisplayName, recipient.EmailAddress, recipient.IsOrganizer); }
public BTree(PSTFile file, BTreePage bTreeRootPage) : base(file) { m_bTreeRootPage = bTreeRootPage; }
// Data tree root is either a single data block, or an XBlock / XXBlock public DataTree(PSTFile file, Block rootBlock) : base(file) { m_bCryptMethod = file.Header.bCryptMethod; m_rootBlock = rootBlock; }
private Block m_rootBlock; // can be DataBlock, XBlock or XXBlock (or null [if we deleted the data tree]) /// <summary> /// Create new data tree /// </summary> public DataTree(PSTFile file) : base(file) { m_bCryptMethod = file.Header.bCryptMethod; m_rootBlock = new DataBlock(m_bCryptMethod); AddBlock(m_rootBlock); }
public static MessageObject GetMessage(PSTFile file, NodeID nodeID) { PSTNode node = file.GetNode(nodeID); return(new MessageObject(node)); }
public static RecurringAppointment CreateNewRecurringAppointment(PSTFile file, NodeID parentNodeID) { return(CreateNewRecurringAppointment(file, parentNodeID, Guid.NewGuid())); }
public Subnode(PSTFile file, NodeID subnodeID, DataTree dataTree, SubnodeBTree subnodeBTree) : base(file, dataTree, subnodeBTree) { m_subnodeID = subnodeID; }
public static TableContext GetAssociatedContentsTableTemplate(PSTFile file) { PSTNode node = file.GetNode(InternalNodeName.NID_ASSOC_CONTENTS_TABLE_TEMPLATE); return(node.TableContext); }
public static TableContext GetHierarchyTableTemplate(PSTFile file) { PSTNode node = file.GetNode(InternalNodeName.NID_HIERARCHY_TABLE_TEMPLATE); return(node.TableContext); }
public static Note CreateNewNote(PSTFile file, NodeID parentNodeID) { return(CreateNewNote(file, parentNodeID, Guid.NewGuid())); }
public void WriteFreeMapPage(PSTFile file, int fMapPageIndex) { long offset = FirstPageOffset + (long)MapppedLength * fMapPageIndex; WriteToStream(file.BaseStream, offset); }