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));
        }
Example #4
0
        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);
        }
Example #5
0
        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));
        }
Example #6
0
        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);
            }
        }
Example #7
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));
        }
Example #8
0
        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;
            }
        }
Example #11
0
        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);
        }
Example #13
0
 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));
        }
Example #15
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);
        }
Example #16
0
        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));
        }
Example #18
0
        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);
 }
Example #21
0
 public BTree(PSTFile file, BTreePage bTreeRootPage) : base(file)
 {
     m_bTreeRootPage = bTreeRootPage;
 }
Example #22
0
 // 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;
 }
Example #23
0
        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()));
 }
Example #26
0
 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);
        }
Example #29
0
 public static Note CreateNewNote(PSTFile file, NodeID parentNodeID)
 {
     return(CreateNewNote(file, parentNodeID, Guid.NewGuid()));
 }
Example #30
0
        public void WriteFreeMapPage(PSTFile file, int fMapPageIndex)
        {
            long offset = FirstPageOffset + (long)MapppedLength * fMapPageIndex;

            WriteToStream(file.BaseStream, offset);
        }