Beispiel #1
0
        /// <summary>eventchaining. We catch this by the baseFeedParsers, which
        /// would not do anything with the gathered data. We pass the event up
        /// to the user</summary>
        /// <param name="sender"> the object which send the event</param>
        /// <param name="e">FeedParserEventArguments, holds the feedentry</param>
        /// <returns> </returns>
        protected void OnParsedNewEntry(object sender, FeedParserEventArgs e)
        {
            if (e == null)
            {
                throw new ArgumentNullException("e");
            }

            if (this.NewAtomEntry != null)
            {
                // just forward it upstream, if hooked
                Tracing.TraceMsg("\t calling event dispatcher");
                this.NewAtomEntry(this, e);
            }
        }
Beispiel #2
0
        /// <summary>converts a form response stream to a TokenCollection,
        /// by parsing the contents of the stream for newlines and equal signs
        /// the input stream is assumed to be an ascii encoded form resonse
        /// </summary>
        /// <param name="inputStream">the stream to read and parse</param>
        /// <returns> the resulting TokenCollection </returns>
        static public TokenCollection ParseStreamInTokenCollection(Stream inputStream)
        {
            // get the body and parse it
            ASCIIEncoding encoder    = new ASCIIEncoding();
            StreamReader  readStream = new StreamReader(inputStream, encoder);
            String        body       = readStream.ReadToEnd();

            readStream.Close();
            Tracing.TraceMsg("got the following body back: " + body);
            // all we are interested is the token, so we break the string in parts
            TokenCollection tokens = new TokenCollection(body, '=', true, 2);

            return(tokens);
        }
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>Event chaining. We catch this by the baseFeedParsers, which
        /// would not do anything with the gathered data. We pass the event up
        /// to the user; if the user doesn't discard it, we add the entry to our
        /// collection</summary>
        /// <param name="sender"> the object which send the event</param>
        /// <param name="e">FeedParserEventArguments, holds the feed entry</param>
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        protected void OnNewExtensionElement(object sender, ExtensionElementEventArgs e)
        {
            // by default, if our event chain is not hooked, the underlying parser will add it
            Tracing.TraceCall("received new extension element notification");
            Tracing.Assert(e != null, "e should not be null");
            if (e == null)
            {
                throw new ArgumentNullException("e");
            }
            if (this.NewExtensionElement != null)
            {
                Tracing.TraceMsg("\t calling event dispatcher");
                this.NewExtensionElement(sender, e);
            }
        }
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>Event chaining. We catch this by the baseFeedParsers, which
        /// would not do anything with the gathered data. We pass the event up
        /// to the user; if the user doesn't discard it, we add the entry to our
        /// collection</summary>
        /// <param name="sender"> the object which send the event</param>
        /// <param name="e">FeedParserEventArguments, holds the feed entry</param>
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        protected void OnParsedNewEntry(object sender, FeedParserEventArgs e)
        {
            // by default, if our event chain is not hooked, add it to the collection
            Tracing.TraceCall("received new item notification");
            Tracing.Assert(e != null, "e should not be null");
            if (e == null)
            {
                throw new ArgumentNullException("e");
            }
            if (this.NewAtomEntry != null)
            {
                Tracing.TraceMsg("\t calling event dispatcher");
                this.NewAtomEntry(this, e);
            }
            // now check the return
            if (!e.DiscardEntry)
            {
                if (!e.CreatingEntry)
                {
                    if (e.Entry != null)
                    {
                        // add it to the collection
                        Tracing.TraceMsg("\t new AtomEntry found, adding to collection");
                        e.Entry.Service = this.Service;
                        this.Entries.Add(e.Entry);
                    }
                    else if (e.Feed != null)
                    {
                        // parsed a feed, set ourselves to it...
                        Tracing.TraceMsg("\t Feed parsed found, parsing is done...");
                    }
                }
                else
                {
                    IVersionAware v = e.Entry as IVersionAware;
                    if (v != null)
                    {
                        v.ProtocolMajor = this.ProtocolMajor;
                        v.ProtocolMinor = this.ProtocolMinor;
                    }
                }
            }

            if (e.DoneParsing)
            {
                this.BaseUriChanged(this.ImpliedBase);
            }
        }
Beispiel #5
0
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>checks if this is a namespace
        /// decl that we already added</summary>
        /// <param name="node">XmlNode to check</param>
        /// <returns>true if this node should be skipped </returns>
        //////////////////////////////////////////////////////////////////////
        protected override bool SkipNode(XmlNode node)
        {
            if (base.SkipNode(node) == true)
            {
                return(true);
            }

            Tracing.TraceMsg("in skipnode for node: " + node.Name + "--" + node.Value);
            if (this.BatchData != null)
            {
                if (node.NodeType == XmlNodeType.Attribute &&
                    (node.Name.StartsWith("xmlns") == true) &&
                    (String.Compare(node.Value, BaseNameTable.gBatchNamespace) == 0))
                {
                    return(true);
                }
            }
            return(false);
        }
        //end of public static String exchangeForSessionToken(String onetimeUseToken, PrivateKey key)



        //////////////////////////////////////////////////////////////////////
        /// <summary>
        /// Exchanges the one time use token returned in the URL for a session
        /// token. If the key is non-null, the token will be used securely,
        /// and the request will be signed
        /// </summary>
        /// <param name="protocol">the protocol to use to communicate with the
        /// server</param>
        /// <param name="domain">the domain at which the authentication server
        /// exists</param>
        /// <param name="onetimeUseToken">the token send by google in the URL</param>
        /// <param name="key">the private key used to sign</param>
        /// <returns>the session token</returns>
        //////////////////////////////////////////////////////////////////////
        public static string exchangeForSessionToken(string protocol,
                                                     string domain,
                                                     string onetimeUseToken,
                                                     AsymmetricAlgorithm key)
        {
            HttpWebResponse response     = null;
            string          authSubToken = null;

            try
            {
                string sessionUrl = getSessionTokenUrl(protocol, domain);
                Uri    uri        = new Uri(sessionUrl);

                HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest;


                string header = formAuthorizationHeader(onetimeUseToken, key, uri, "GET");
                request.Headers.Add(header);

                response = request.GetResponse() as HttpWebResponse;
            }
            catch (WebException e)
            {
                Tracing.TraceMsg("exchangeForSessionToken failed " + e.Status);
                throw new GDataRequestException("Execution of exchangeForSessionToken", e);
            }
            if (response != null)
            {
                int code = (int)response.StatusCode;
                if (code != 200)
                {
                    throw new GDataRequestException("Execution of exchangeForSessionToken request returned unexpected result: " + code, response);
                }
                // get the body and parse it
                authSubToken = Utilities.ParseValueFormStream(response.GetResponseStream(), GoogleAuthentication.AuthSubToken);
            }

            Tracing.Assert(authSubToken != null, "did not find an auth token in exchangeForSessionToken");

            return(authSubToken);
        }
        //////////////////////////////////////////////////////////////////////
        /// <summary>Retrieves information about the AuthSub token.
        /// If the <code>key</code> is non-null, the token will be used securely
        /// and the request to revoke the token will be signed.
        /// </summary>
        /// <param name="protocol">the protocol to use to communicate with the server</param>
        /// <param name="domain">the domain at which the authentication server exists</param>
        /// <param name="token">tthe AuthSub token for which to receive information </param>
        /// <param name="key">the private key to sign the request</param>
        /// <returns>the token information in the form of a Dictionary from the name of the
        ///  attribute to the value of the attribute</returns>
        //////////////////////////////////////////////////////////////////////
        public static Dictionary <String, String> GetTokenInfo(String protocol,
                                                               String domain,
                                                               String token,
                                                               AsymmetricAlgorithm key)
        {
            HttpWebResponse response;

            try
            {
                string tokenInfoUrl = GetTokenInfoUrl(protocol, domain);
                Uri    uri          = new Uri(tokenInfoUrl);

                HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest;


                string header = formAuthorizationHeader(token, key, uri, "GET");
                request.Headers.Add(header);

                response = request.GetResponse() as HttpWebResponse;
            }
            catch (WebException e)
            {
                Tracing.TraceMsg("GetTokenInfo failed " + e.Status);
                throw new GDataRequestException("Execution of GetTokenInfo", e);
            }

            if (response != null)
            {
                int code = (int)response.StatusCode;
                if (code != 200)
                {
                    throw new GDataRequestException("Execution of revokeToken request returned unexpected result: " + code, response);
                }
                TokenCollection tokens = Utilities.ParseStreamInTokenCollection(response.GetResponseStream());
                if (tokens != null)
                {
                    return(tokens.CreateDictionary());
                }
            }
            return(null);
        }
        //end of private static string generateULONGRnd()



        //////////////////////////////////////////////////////////////////////
        /// <summary>signs the data with the given key</summary>
        /// <param name="dataToSign">the data to sign </param>
        /// <param name="key">the private key to used </param>
        /// <returns> the signed data</returns>
        //////////////////////////////////////////////////////////////////////
        private static byte[]  sign(string dataToSign, AsymmetricAlgorithm key)
        {
            byte[] data = new ASCIIEncoding().GetBytes(dataToSign);

            try
            {
                RSACryptoServiceProvider providerRSA = key as RSACryptoServiceProvider;
                if (providerRSA != null)
                {
                    return(providerRSA.SignData(data, new SHA1CryptoServiceProvider()));
                }
                DSACryptoServiceProvider providerDSA = key as DSACryptoServiceProvider;
                if (providerDSA != null)
                {
                    return(providerDSA.SignData(data));
                }
            }
            catch (CryptographicException e)
            {
                Tracing.TraceMsg(e.Message);
            }
            return(null);
        }
Beispiel #9
0
        /// <summary>
        /// Parses the inner state of the element
        /// </summary>
        /// <param name="e">The extension element that should be added to this entry</param>
        /// <param name="parser">The AtomFeedParser that called this</param>
        public virtual void Parse(ExtensionElementEventArgs e, AtomFeedParser parser)
        {
            if (e == null)
            {
                throw new ArgumentNullException("e");
            }

            Tracing.TraceMsg("Entering Parse on AbstractEntry");
            XmlNode node = e.ExtensionElement;

            if (this.ExtensionFactories != null && this.ExtensionFactories.Count > 0)
            {
                Tracing.TraceMsg("Entring default Parsing for AbstractEntry");

                IExtensionElementFactory f = FindExtensionFactory(node.LocalName,
                                                                  node.NamespaceURI);
                if (f != null)
                {
                    this.ExtensionElements.Add(f.CreateInstance(node, parser));
                    e.DiscardEntry = true;
                }
            }
        }
Beispiel #10
0
        ///<summary>Deletes an Atom entry when given a Uri</summary>
        ///<param name="uriTarget">The target Uri to call http delete against</param>
        ///<param name="eTag">The eTag of the item to delete. This parameter is used for strong
        /// concurrency support in protocol version 2 and up</param>
        public void Delete(Uri uriTarget, string eTag)
        {
            Tracing.Assert(uriTarget != null, "uri should not be null");
            if (uriTarget == null)
            {
                throw new ArgumentNullException("uriTarget");
            }

            Tracing.TraceMsg("Deleting entry: " + uriTarget.ToString());
            IGDataRequest request = RequestFactory.CreateRequest(GDataRequestType.Delete, uriTarget);

            ISupportsEtag eTarget = request as ISupportsEtag;

            if (eTarget != null && eTag != null)
            {
                eTarget.Etag = eTag;
            }

            request.Credentials = Credentials;
            request.Execute();
            IDisposable disp = request as IDisposable;

            disp.Dispose();
        }
Beispiel #11
0
        /// <summary>sets up the correct credentials for this call, pending 
        /// security scheme</summary> 
        protected override void EnsureCredentials() {
            Tracing.Assert(this.Request != null, "We should have a webrequest now");
            if (this.Request == null) {
                return;
            }

            // if the token is NULL, we need to get a token. 
            if (this.factory.GAuthToken == null) {
                // we will take the standard credentials for that
                GDataCredentials gc = this.Credentials;
                Tracing.TraceMsg(gc == null ? "No Network credentials set" : "Network credentials found");
                if (gc != null) {
                    // only now we have something to do... 
                    this.factory.GAuthToken = QueryAuthToken(gc);
                }
            }

            if (this.factory.GAuthToken != null && this.factory.GAuthToken.Length > 0) {
                // Tracing.Assert(this.factory.GAuthToken != null, "We should have a token now"); 
                Tracing.TraceMsg("Using auth token: " + this.factory.GAuthToken);
                string strHeader = GoogleAuthentication.Header + this.factory.GAuthToken;
                this.Request.Headers.Add(strHeader);
            }
        }
Beispiel #12
0
        /// <summary>public WebResponse Insert(Uri insertUri, Stream entryStream, ICredentials credentials)</summary>
        /// <param name="feed">the feed this entry should be inserted into</param>
        /// <param name="entry">the entry to be inserted</param>
        /// <returns> the inserted entry</returns>
        AtomEntry IService.Insert(AtomFeed feed, AtomEntry entry)
        {
            Tracing.Assert(feed != null, "feed should not be null");
            if (feed == null)
            {
                throw new ArgumentNullException("feed");
            }

            Tracing.Assert(entry != null, "entry should not be null");
            if (entry == null)
            {
                throw new ArgumentNullException("entry");
            }

            if (feed.ReadOnly)
            {
                throw new GDataRequestException("Can not update a read-only feed");
            }

            Tracing.TraceMsg("Post URI is: " + feed.Post);
            Uri target = new Uri(feed.Post);

            return(Insert(target, entry));
        }
 public override void Execute()
 {
     try {
         base.Execute();
     } catch (GDataRequestException re) {
         HttpWebResponse webResponse = re.Response as HttpWebResponse;
         if (webResponse != null && webResponse.StatusCode == HttpStatusCode.Unauthorized)
         {
             Tracing.TraceMsg("Access token might have expired, refreshing.");
             Reset();
             try {
                 OAuthUtil.RefreshAccessToken(this.factory.Parameters);
             } catch (WebException e) {
                 Tracing.TraceMsg("Failed to refresh access token: " + e.StackTrace);
                 throw re;
             }
             base.Execute();
         }
         else
         {
             throw;
         }
     }
 }
        /// <summary>
        /// event on the Feed to handle extension elements during parsing
        /// </summary>
        /// <param name="e">the event arguments</param>
        /// <param name="parser">the parser that caused this</param>
        protected virtual void HandleExtensionElements(ExtensionElementEventArgs e, AtomFeedParser parser)
        {
            Tracing.TraceMsg("Entering HandleExtensionElements on AbstractFeed");
            XmlNode node = e.ExtensionElement;

            if (this.ExtensionFactories != null && this.ExtensionFactories.Count > 0)
            {
                Tracing.TraceMsg("Entring default Parsing for AbstractFeed");
                foreach (IExtensionElementFactory f in this.ExtensionFactories)
                {
                    Tracing.TraceMsg("Found extension Factories");
                    if (String.Compare(node.NamespaceURI, f.XmlNameSpace, true, CultureInfo.InvariantCulture) == 0)
                    {
                        if (String.Compare(node.LocalName, f.XmlName, true, CultureInfo.InvariantCulture) == 0)
                        {
                            e.Base.ExtensionElements.Add(f.CreateInstance(node, parser));
                            e.DiscardEntry = true;
                            break;
                        }
                    }
                }
            }
            return;
        }
        /////////////////////////////////////////////////////////////////////////////



        //////////////////////////////////////////////////////////////////////
        /// <summary>Executes the request and prepares the response stream. Also
        /// does error checking</summary>
        /// <param name="retryCounter">indicates the n-th time this is run</param>
        //////////////////////////////////////////////////////////////////////
        protected void Execute(int retryCounter)
        {
            Tracing.TraceCall("GoogleAuth: Execution called");
            try
            {
                CopyRequestData();
                base.Execute();
                if (this.Response is HttpWebResponse)
                {
                    HttpWebResponse response = this.Response as HttpWebResponse;
                    this.responseVersion = new VersionInformation(response.Headers[GDataGAuthRequestFactory.GDataVersion]);
                }
            }
            catch (GDataForbiddenException)
            {
                Tracing.TraceMsg("need to reauthenticate, got a forbidden back");
                // do it again, once, reset AuthToken first and streams first
                Reset();
                this.factory.GAuthToken = null;
                CopyRequestData();
                base.Execute();
            }
            catch (GDataRedirectException re)
            {
                // we got a redirect.
                Tracing.TraceMsg("Got a redirect to: " + re.Location);
                // only reset the base, the auth cookie is still valid
                // and cookies are stored in the factory
                if (this.factory.StrictRedirect == true)
                {
                    HttpWebRequest http = this.Request as HttpWebRequest;
                    if (http != null)
                    {
                        // only redirect for GET, else throw
                        if (http.Method != HttpMethods.Get)
                        {
                            throw;
                        }
                    }
                }

                // verify that there is a non empty location string
                if (re.Location.Trim().Length == 0)
                {
                    throw;
                }

                Reset();
                this.TargetUri = new Uri(re.Location);
                CopyRequestData();
                base.Execute();
            }
            catch (GDataRequestException)
            {
                if (retryCounter > this.factory.NumberOfRetries)
                {
                    Tracing.TraceMsg("Number of retries exceeded");
                    throw;
                }
                Tracing.TraceMsg("Let's retry this");
                // only reset the base, the auth cookie is still valid
                // and cookies are stored in the factory
                Reset();
                this.Execute(retryCounter + 1);
            }
            catch (Exception e)
            {
                Tracing.TraceCall("*** EXCEPTION " + e.GetType().Name + " CAUGTH ***");
                throw;
            }
            finally
            {
                if (this.requestCopy != null)
                {
                    this.requestCopy.Close();
                    this.requestCopy = null;
                }
            }
        }
Beispiel #16
0
        /// <summary>Executes the request and prepares the response stream. Also
        /// does error checking</summary>
        public virtual void Execute()
        {
            try {
                EnsureWebRequest();
                // if we ever handed out a stream, we want to close it before doing the real excecution
                if (this.requestStream != null)
                {
                    this.requestStream.Close();
                }

                Tracing.TraceCall("calling the real execution over the webresponse");
                LogRequest(this.webRequest);
                this.webResponse = this.webRequest.GetResponse();
            } catch (WebException e) {
                Tracing.TraceCall("GDataRequest::Execute failed: " + this.targetUri.ToString());
                GDataRequestException gde = new GDataRequestException("Execution of request failed: " + this.targetUri.ToString(), e);
                throw gde;
            }

            if (this.webResponse != null)
            {
                this.responseStream = this.webResponse.GetResponseStream();
            }

            LogResponse(this.webResponse);
            if (this.webResponse is HttpWebResponse)
            {
                HttpWebResponse response = this.webResponse as HttpWebResponse;
                HttpWebRequest  request  = this.webRequest as HttpWebRequest;

                this.useGZip = (string.Compare(response.ContentEncoding, "gzip", true, CultureInfo.InvariantCulture) == 0);
                if (this.useGZip)
                {
                    this.responseStream = new GZipStream(this.responseStream, CompressionMode.Decompress);
                }

                Tracing.Assert(response != null, "The response should not be NULL");
                Tracing.Assert(request != null, "The request should not be NULL");

                int code = (int)response.StatusCode;

                Tracing.TraceMsg("Returned ContentType is: " + (response.ContentType == null ? "None" : response.ContentType) + " from URI : " + request.RequestUri.ToString());;
                Tracing.TraceMsg("Returned StatusCode is: " + response.StatusCode + code);

                if (response.StatusCode == HttpStatusCode.Forbidden)
                {
                    // that could imply that we need to reauthenticate
                    Tracing.TraceMsg("need to reauthenticate");
                    throw new GDataForbiddenException("Execution of request returned HttpStatusCode.Forbidden: " +
                                                      this.targetUri.ToString() + response.StatusCode.ToString(), this.webResponse);
                }

                if (response.StatusCode == HttpStatusCode.Conflict)
                {
                    // a put went bad due to a version conflict
                    throw new GDataVersionConflictException("Execution of request returned HttpStatusCode.Conflict: " +
                                                            this.targetUri.ToString() + response.StatusCode.ToString(), this.webResponse);
                }

                if ((this.IfModifiedSince != DateTime.MinValue || this.Etag != null) &&
                    response.StatusCode == HttpStatusCode.NotModified)
                {
                    // Throw an exception for conditional GET
                    throw new GDataNotModifiedException("Content not modified: " + this.targetUri.ToString(), this.webResponse);
                }

                if (response.StatusCode == HttpStatusCode.Redirect ||
                    response.StatusCode == HttpStatusCode.Found ||
                    response.StatusCode == HttpStatusCode.RedirectKeepVerb)
                {
                    Tracing.TraceMsg("throwing for redirect");
                    throw new GDataRedirectException("Execution resulted in a redirect from " + this.targetUri.ToString(), this.webResponse);
                }

                if (code > 299)
                {
                    // treat everything else over 300 as errors
                    throw new GDataRequestException("Execution of request returned unexpected result: " + this.targetUri.ToString() +
                                                    response.StatusCode.ToString(), this.webResponse);
                }

                this.contentLength = response.ContentLength;

                // if we got an etag back, remember it
                this.eTag = response.Headers[GDataRequestFactory.EtagHeader];

                response = null;
                request  = null;
            }
        }
Beispiel #17
0
       /// <summary>Executes the request and prepares the response stream. Also 
       /// does error checking</summary> 
       /// <param name="retryCounter">indicates the n-th time this is run</param>
       protected void Execute(int retryCounter) {
           Tracing.TraceCall("GoogleAuth: Execution called");
           try {n);
               CopyRequestData();
               base.Execute();
            if (this.Response is HttpWebResponse) {
                   HttpWebResponse response = this.Response as HttpWebResponse;
                   this.responseVersion = new VersionInformation(response.Headers[GDataGAuthRequestFactory.GDataVersion]);
               }
           } catch (GDataForbiddenException) {
               Tracing.TraceMsg("need to reauthenticate, got a forbidden back");
               // do it again, once, reset AuthToken first and streams first
               Reset();
               this.factory.GAuthToken = null;n);
               CopyRequestData();
               base.Execute();
          catch (GDataRedirectException re) {
               // we got a redirect.
               Tracing.TraceMsg("Got a redirect to: " + re.Location);
               // only reset the base, the auth cookie is still valid
               // and cookies are stored in the factory
               if (this.factory.StrictRedirect) {
                   HttpWebRequest http = this.Request as HttpWebRequest;
                   if (http != null) {
                       // only redirect for GET, else throw
                       if (http.Method != HttpMethods.Get) {
                           throw;e; 
                       }
                   }
               
               // verify that there is a non empty location string
               if (re.Location.Trim().Length == 0) {
                   throw;
               }
 }
            se.Reset();
               this.TargetUri = new Uri(re.Location);
               CopyRequestData();
               base.Execute();
          catch (GDataRequestException re) {
               HttpWebResponse webResponse = re.Response as HttpWebResponse;
               if (webResponse != null && webResponse.StatusCode != HttpStatusCode.InternalServerError) {
                   Tracing.TraceMsg("Not a server error. Possibly a Bad request or forbidden resource.");
                   Tracing.TraceMsg("We don't want to retry non 500 errors.");
                   throw;
               }  {
               iretryCountering > this.factory.NumberOfRetri    {
                   Tracing.TraceMsNumber of retries exceededect");
                   throw re;
               }
               Tracing.TraceMsg("Let's retry tis"); 
               // only reset the base, the auth cookie is still valid
               // and cookies are stored in the factory
          base.Reset();
               this.ExretryCountertrying
           } catch (Exception e)       {
               Tracing.TraceCall("*** EXCEPTION " + e.GetType().Name + HTCAUGTH ***");
               
           } finally {
               if (this.requestCopy != null) {
                   this.requestCopy.Close();
                   this.requestCopy = null;
               }
           }
       }
Beispiel #18
0
 //////////////////////////////////////////////////////////////////////
 /// <summary>Method to trace the current call with an additional message</summary>
 /// <param name="msg"> msg string to display</param>
 //////////////////////////////////////////////////////////////////////
 [Conditional("TRACE")] static public void TraceInfo(string msg)
 {
     Tracing.TraceMsg(msg);
 }
Beispiel #19
0
        /// <summary>saves the inner state of the element</summary>
        /// <param name="writer">the xmlWriter to save into </param>
        protected override void SaveInnerXml(XmlWriter writer)
        {
            // saving title
            Tracing.TraceMsg("Entering save inner XML on AtomEntry");

            if (this.batchData != null)
            {
                this.batchData.Save(writer);
            }

            if (this.title != null)
            {
                Tracing.TraceMsg("Saving Title: " + this.Title.Text);
                this.Title.SaveToXml(writer);
            }

            if (this.id != null)
            {
                this.Id.SaveToXml(writer);
            }

            foreach (AtomLink link in this.Links)
            {
                link.SaveToXml(writer);
            }

            foreach (AtomPerson person in this.Authors)
            {
                person.SaveToXml(writer);
            }

            foreach (AtomPerson person in this.Contributors)
            {
                person.SaveToXml(writer);
            }

            foreach (AtomCategory category in this.Categories)
            {
                category.SaveToXml(writer);
            }

            if (this.rights != null)
            {
                this.Rights.SaveToXml(writer);
            }

            if (this.summary != null)
            {
                this.Summary.SaveToXml(writer);
            }

            if (this.content != null)
            {
                this.Content.SaveToXml(writer);
            }

            if (this.source != null)
            {
                this.Source.SaveToXml(writer);
            }

            WriteLocalDateTimeElement(writer, AtomParserNameTable.XmlUpdatedElement, this.Updated);
            WriteLocalDateTimeElement(writer, AtomParserNameTable.XmlPublishedElement, this.Published);
        }
        /// <summary>goes to the Google auth service, and gets a new auth token</summary>
        /// <returns>the auth token, or NULL if none received</returns>
        public static string QueryClientLoginToken(GDataCredentials gc,
                                                   string serviceName,
                                                   string applicationName,
                                                   bool fUseKeepAlive,
                                                   IWebProxy proxyServer,
                                                   Uri clientLoginHandler)
        {
            Tracing.Assert(gc != null, "Do not call QueryAuthToken with no network credentials");
            if (gc == null)
            {
                throw new System.ArgumentNullException("nc", "No credentials supplied");
            }

            HttpWebRequest authRequest = WebRequest.Create(clientLoginHandler) as HttpWebRequest;

            authRequest.KeepAlive = fUseKeepAlive;

            if (proxyServer != null)
            {
                authRequest.Proxy = proxyServer;
            }

            string accountType = GoogleAuthentication.AccountType;

            if (!String.IsNullOrEmpty(gc.AccountType))
            {
                accountType += gc.AccountType;
            }
            else
            {
                accountType += GoogleAuthentication.AccountTypeDefault;
            }

            WebResponse     authResponse = null;
            HttpWebResponse response     = null;

            string authToken = null;

            try {
                authRequest.ContentType = HttpFormPost.Encoding;
                authRequest.Method      = HttpMethods.Post;
                ASCIIEncoding encoder = new ASCIIEncoding();

                string user = gc.Username == null ? "" : gc.Username;
                string pwd  = gc.getPassword() == null ? "" : gc.getPassword();

                // now enter the data in the stream
                string postData = GoogleAuthentication.Email + "=" + Utilities.UriEncodeUnsafe(user) + "&";
                postData += GoogleAuthentication.Password + "=" + Utilities.UriEncodeUnsafe(pwd) + "&";
                postData += GoogleAuthentication.Source + "=" + Utilities.UriEncodeUnsafe(applicationName) + "&";
                postData += GoogleAuthentication.Service + "=" + Utilities.UriEncodeUnsafe(serviceName) + "&";
                if (gc.CaptchaAnswer != null)
                {
                    postData += GoogleAuthentication.CaptchaAnswer + "=" + Utilities.UriEncodeUnsafe(gc.CaptchaAnswer) + "&";
                }
                if (gc.CaptchaToken != null)
                {
                    postData += GoogleAuthentication.CaptchaToken + "=" + Utilities.UriEncodeUnsafe(gc.CaptchaToken) + "&";
                }
                postData += accountType;

                byte[] encodedData = encoder.GetBytes(postData);
                authRequest.ContentLength = encodedData.Length;

                Stream requestStream = authRequest.GetRequestStream();
                requestStream.Write(encodedData, 0, encodedData.Length);
                requestStream.Close();
                authResponse = authRequest.GetResponse();
                response     = authResponse as HttpWebResponse;
            } catch (WebException e) {
                response = e.Response as HttpWebResponse;
                if (response == null)
                {
                    Tracing.TraceMsg("QueryAuthtoken failed " + e.Status + " " + e.Message);
                    throw;
                }
            }

            if (response != null)
            {
                // check the content type, it must be text
                if (!response.ContentType.StartsWith(HttpFormPost.ReturnContentType))
                {
                    throw new GDataRequestException("Execution of authentication request returned unexpected content type: " + response.ContentType, response);
                }

                TokenCollection tokens = Utilities.ParseStreamInTokenCollection(response.GetResponseStream());
                authToken = Utilities.FindToken(tokens, GoogleAuthentication.AuthToken);

                if (authToken == null)
                {
                    throw Utilities.getAuthException(tokens, response);
                }

                // failsafe. if getAuthException did not catch an error...
                int code = (int)response.StatusCode;
                if (code != 200)
                {
                    throw new GDataRequestException("Execution of authentication request returned unexpected result: " + code, response);
                }
            }

            Tracing.Assert(authToken != null, "did not find an auth token in QueryAuthToken");
            if (authResponse != null)
            {
                authResponse.Close();
            }

            return(authToken);
        }