internal MailBatchDatum(FolderModel folderModel,
                         string mailId,
                         string messageHead) {
   this.FolderModel = folderModel;
   this.MailId = mailId;
   this.MessageHead = messageHead;
   this.uploaded = true;
 }
    /// <summary>
    /// Persists the selection state, uploaded mail count, failed mail count and
    /// last uplaoded mail id. Ten recurses to persist all the sub folders.
    /// </summary>
    void SaveFolderModelState(XmlElement parentXmlElement,
                              FolderModel folderModel) {
      XmlElement folderXmlElement =
          this.xmlDocument.CreateElement(LKGStatePersistor.FolderElementName);
      parentXmlElement.AppendChild(folderXmlElement);
      folderXmlElement.SetAttribute(
          LKGStatePersistor.NameAttrName,
          folderModel.Folder.Name);
      folderXmlElement.SetAttribute(
          LKGStatePersistor.SelectionStateAttrName,
          folderModel.IsSelected.ToString());

      foreach (string mailId in folderModel.MailUploadData.Keys) {
        XmlElement uploadedEmailXmlElement =
            this.xmlDocument.CreateElement(
                LKGStatePersistor.MailElementName);
        folderXmlElement.AppendChild(uploadedEmailXmlElement);
        uploadedEmailXmlElement.SetAttribute(
            LKGStatePersistor.MailIdAttrName,
            mailId);
        FailedMailDatum failedMailDatum =
            (FailedMailDatum)folderModel.MailUploadData[mailId];
        if (failedMailDatum != null) {
          // In case of failure to upload we set the reason, otherwise not.
          uploadedEmailXmlElement.SetAttribute(
              LKGStatePersistor.FailureReasonAttrName,
              failedMailDatum.FailureReason);
          uploadedEmailXmlElement.InnerText = failedMailDatum.MailHead;
        }
      }
      foreach (FolderModel childFolderModel in folderModel.Children) {
        this.SaveFolderModelState(
            folderXmlElement,
            childFolderModel);
      }
    }
 /// <summary>
 /// Loads the folder state i.e. SelectionState, UploadedMailCount,
 /// FailedMailCount, LastUploadedMailId. Then it recurses on the
 /// sub folders.
 /// </summary>
 void LoadFolderModelState(XmlElement folderXmlElement,
                           FolderModel folderModel) {
   LKGStatePersistor.LoadSelectedState(
       folderXmlElement,
       folderModel);
   foreach (XmlNode childXmlNode in folderXmlElement.ChildNodes) {
     XmlElement childXmlElement = childXmlNode as XmlElement;
     if (childXmlElement == null) {
       continue;
     }
     if (childXmlElement.Name != LKGStatePersistor.MailElementName) {
       continue;
     }
     string mailId =
         childXmlElement.GetAttribute(LKGStatePersistor.MailIdAttrName);
     if (mailId == null || mailId.Length == 0) {
       continue;
     }
     string failureReason =
         childXmlElement.GetAttribute(
             LKGStatePersistor.FailureReasonAttrName);
     if (failureReason == null || failureReason.Length == 0) {
       folderModel.SuccessfullyUploaded(mailId);
     } else {
       FailedMailDatum failedMailDatum =
         new FailedMailDatum(childXmlElement.InnerText, failureReason);
       folderModel.FailedToUpload(mailId, failedMailDatum);
     }
   }
   this.LoadFolderModelsState(
       folderXmlElement.ChildNodes,
       folderModel.Children);
 }
 bool MoveToNextNonEmptySelectedFolder() {
   this.DisposeCurrentEnumerator();
   while (this.folderIterationIndex < this.folderModelFlatList.Count) {
     this.currentFolderModel =
         (FolderModel)this.folderModelFlatList[this.folderIterationIndex];
     this.folderIterationIndex++;
     if (!this.currentFolderModel.IsSelected ||
         this.currentFolderModel.Folder.MailCount == 0) {
       continue;
     }
     this.currentFolderEnumerator =
         this.currentFolderModel.Folder.Mails.GetEnumerator();
     if (!this.currentFolderEnumerator.MoveNext()) {
       // We reached the end of the folder
       // so dispose enumerator and continue with the next folder.
       this.DisposeCurrentEnumerator();
       continue;
     }
     // There are mails and current points to the mail to be uploaded.
     return true;
   }
   this.currentFolderModel = null;
   return false;
 }
    internal unsafe bool AddMail(IMail mail,
                                 FolderModel folderModel) {
      byte[] rfc822Buffer = mail.Rfc822Buffer;
      Debug.Assert(rfc822Buffer.Length > 0 &&
          rfc822Buffer.Length <= GoogleEmailUploaderConfig.MaximumBatchSize);
      bool canAdd = (
          // If its multimail batch let it be almost default mail batch size
          this.mailCount > 0 &&
          this.MemoryStream.Length + rfc822Buffer.Length + 2048
            <= GoogleEmailUploaderConfig.NormalBatchSize &&
          this.mailCount < GoogleEmailUploaderConfig.MaximumMailsPerBatch
        ) || (
          // If this mail is HUGE then its ok to be in singleton batch.
          this.mailCount == 0 &&
          rfc822Buffer.Length <=
              GoogleEmailUploaderConfig.MaximumBatchSize);

      if (!canAdd) {
        return false;
      }

      this.batchXmlTextWriter.WriteStartElement(MailBatch.EntryElementName,
                                                MailBatch.AtomNS);
      {
        // Add the category element to the feed.
        this.batchXmlTextWriter.WriteStartElement("category",
                                                  MailBatch.AtomNS);
        this.batchXmlTextWriter.WriteAttributeString("scheme",
                                                     MailBatch.GDataKindURI);
        this.batchXmlTextWriter.WriteAttributeString("term",
                                                     MailBatch.AppsMailItemURI);
        this.batchXmlTextWriter.WriteEndElement();
      }
      // Write out batchId
      {
        this.batchXmlTextWriter.WriteStartElement(MailBatch.IdElementName,
                                                  MailBatch.GDataBatchNS);
        this.batchXmlTextWriter.WriteString(this.mailCount.ToString());
        this.batchXmlTextWriter.WriteEndElement();
      }
      // Write out rfc822...
      {
        bool containsNonPrintASCII = false;
        // This test is rough. utf8 is multi byte, so having the illegal xml
        // byte need not mean its illegal xml. We could send every thing as
        // base64. This just helps us to optimize saving bytes on the wire.
        for (int i = 0; i < rfc822Buffer.Length; ++i) {
          byte b = rfc822Buffer[i];
          if (b >= 0x80 ||
              !MailBatch.IsPrintableAscii[b]) {
            containsNonPrintASCII = true;
            break;
          }
        }
        this.batchXmlTextWriter.WriteStartElement("rfc822Msg",
                                                  MailBatch.AppsNS);
        if (containsNonPrintASCII) {
          // If the rfc822 contains illegal xml chars then
          // we use base64 encoding.
          this.batchXmlTextWriter.WriteAttributeString("encoding",
                                                       "base64");
          this.batchXmlTextWriter.WriteBase64(rfc822Buffer,
                                              0,
                                              rfc822Buffer.Length);
        } else {
          // Otherwise we embed the rfc as is.
          string rfcString = Encoding.UTF8.GetString(rfc822Buffer);
          this.batchXmlTextWriter.WriteString(rfcString);
        }
        this.batchXmlTextWriter.WriteEndElement();
      }
      // Write out mail item properties except IS_TRASH. We will not move
      // anything to Trash folder as it automatically empties the Trash.
      {
        if (!mail.IsRead) {
          this.batchXmlTextWriter.WriteStartElement("mailItemProperty",
                                                    MailBatch.AppsNS);
          this.batchXmlTextWriter.WriteAttributeString("value",
                                                       "IS_UNREAD");
          this.batchXmlTextWriter.WriteEndElement();
        }
        if (mail.IsStarred) {
          this.batchXmlTextWriter.WriteStartElement("mailItemProperty",
                                                    MailBatch.AppsNS);
          this.batchXmlTextWriter.WriteAttributeString("value",
                                                       "IS_STARRED");
          this.batchXmlTextWriter.WriteEndElement();
        }
        if (MailBatch.IsAncestor(mail.Folder, FolderKind.Inbox) &&
            !this.GoogleEmailUploaderModel.IsArchiveEverything) {
          this.batchXmlTextWriter.WriteStartElement("mailItemProperty",
                                                    MailBatch.AppsNS);
          this.batchXmlTextWriter.WriteAttributeString("value",
                                                       "IS_INBOX");
          this.batchXmlTextWriter.WriteEndElement();
        }
        if (MailBatch.IsAncestor(mail.Folder, FolderKind.Sent)) {
          this.batchXmlTextWriter.WriteStartElement("mailItemProperty",
                                                    MailBatch.AppsNS);
          this.batchXmlTextWriter.WriteAttributeString("value",
                                                       "IS_SENT");
          this.batchXmlTextWriter.WriteEndElement();
        }
        if (MailBatch.IsAncestor(mail.Folder, FolderKind.Draft)) {
          this.batchXmlTextWriter.WriteStartElement("mailItemProperty",
                                                    MailBatch.AppsNS);
          this.batchXmlTextWriter.WriteAttributeString("value",
                                                       "IS_DRAFT");
          this.batchXmlTextWriter.WriteEndElement();
        }
      }

      // Write out labels...
      {
        string[] labels = folderModel.Labels;
        for (int i = 0; i < labels.Length; ++i) {
          this.batchXmlTextWriter.WriteStartElement("label",
                                                    MailBatch.AppsNS);
          this.batchXmlTextWriter.WriteAttributeString("labelName",
                                                       labels[i]);
          this.batchXmlTextWriter.WriteEndElement();
        }
      }
      this.batchXmlTextWriter.WriteEndElement();

      this.mailCount++;
      this.lastAddedFolderModel = folderModel;
      MailBatchDatum batchData =
          new MailBatchDatum(folderModel,
                             mail.MailId,
                             MailBatch.GetMailHeader(mail));
      this.MailBatchData.Add(batchData);
      return true;
    }
 internal void StartBatch() {
   this.MemoryStream.Position = 0;
   this.MemoryStream.SetLength(0);
   this.mailCount = 0;
   this.MailBatchData.Clear();
   this.lastAddedFolderModel = null;
   this.batchXmlTextWriter = new XmlTextWriter(this.MemoryStream,
                                          Encoding.UTF8);
   this.batchXmlTextWriter.Formatting = Formatting.Indented;
   // Start the document
   this.batchXmlTextWriter.WriteStartDocument();
   // Start the feed...
   this.batchXmlTextWriter.WriteStartElement("a",
                                             MailBatch.FeedElementName,
                                             MailBatch.AtomNS);
   this.batchXmlTextWriter.WriteAttributeString("xmlns",
                                                "app",
                                                MailBatch.XmlNS,
                                                MailBatch.AppsNS);
   this.batchXmlTextWriter.WriteAttributeString("xmlns",
                                                "batch",
                                                MailBatch.XmlNS,
                                                MailBatch.GDataBatchNS);
   this.startDateTime = DateTime.Now;
 }