3
\$\begingroup\$

I have the following code for importing Yahoo contacts from an address book, but it imports only the top 30 contacts, not all of the contacts.

Anyways, I think another alternative (and better) way of doing it is by using another latest Yahoo API.

        private const string _addressBookUrl = "http://address.mail.yahoo.com/allcontacts";
        //private const string _addressBookUrl = "http://address.yahoo.com/yab/us/Yahoo_ab.csv?loc=us&.rand=1671497644&A=H&Yahoo_ab.csv";  
        private const string _authUrl = "https://login.yahoo.com/config/login?";
        private const string _loginPage = "https://login.yahoo.com/config/login";
        private const string _userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3";

    [TestMethod()]
    public void Yahoo()
    {
       List<ContactDetails> lst = new List<ContactDetails>();
       lst = GetYahooContacts("UserId", "Password");
       Assert.IsNotNull(lst);
    }


    public List<ContactDetails> GetYahooContacts(string _username, string _pass)
    {
        try
        {
            WebClient webclient = new WebClient();
            webclient.Headers[HttpRequestHeader.UserAgent] = _userAgent;
            webclient.Encoding = Encoding.UTF8;

            byte[] firstResponse = webclient.DownloadData(_loginPage);                
            string firstRes = Encoding.UTF8.GetString(firstResponse);

            NameValueCollection postToLogin = new NameValueCollection();
            Regex regex = new Regex("type=\"hidden\" name=\"(.*?)\" value=\"(.*?)\"", RegexOptions.IgnoreCase);
            Match match = regex.Match(firstRes);
            while (match.Success)
            {
                if (match.Groups[0].Value.Length > 0)
                {
                    postToLogin.Add(match.Groups[1].Value, match.Groups[2].Value);
                }
                match = regex.Match(firstRes, match.Index + match.Length);
            }

            postToLogin.Add(".save", "Sign In");
            postToLogin.Add(".persistent", "y");

            string login = _username;
            postToLogin.Add("login", login);
            postToLogin.Add("passwd", _pass);

            webclient.Headers[HttpRequestHeader.UserAgent] = _userAgent;
            webclient.Headers[HttpRequestHeader.Referer] = _loginPage;
            webclient.Encoding = Encoding.UTF8;
            webclient.Headers[HttpRequestHeader.Cookie] = webclient.ResponseHeaders[HttpResponseHeader.SetCookie];

            webclient.UploadValues(_authUrl, postToLogin);

            string cookie = webclient.ResponseHeaders[HttpResponseHeader.SetCookie];


            string newCookie = string.Empty;
            string[] tmp1 = cookie.Split(',');
            foreach (string var in tmp1)
            {
                string[] tmp2 = var.Split(';');
                newCookie = String.IsNullOrEmpty(newCookie) ? tmp2[0] : newCookie + ";" + tmp2[0];
            }

            webclient.Headers[HttpRequestHeader.Cookie] = newCookie;
            byte[] thirdResponse = webclient.DownloadData(_addressBookUrl);                
            string thirdRes = Encoding.UTF8.GetString(thirdResponse);
            List<ContactDetails> lst = new List<ContactDetails>();
            lst = ParseYahooResponse(thirdRes);
            return lst;
        }
        catch (Exception e)
        {
            throw e;
        }
    }


    private List<ContactDetails> ParseYahooResponse(string _response)
    {
        List<ContactDetails> ContactList = new List<ContactDetails>();
        _response = _response.Substring(_response.IndexOf("InitialContacts"), (_response.IndexOf("InitialBucket") - _response.IndexOf("InitialContacts")));

        List<YahooContacts> Contacts = JsonConvert.DeserializeObject<List<YahooContacts>>(_response.Substring(_response.IndexOf('['), (_response.LastIndexOf(']') - _response.IndexOf('[')) + 1));

        foreach (YahooContacts oYahooContacts in Contacts)
        {
            ContactDetails ocontacts = new ContactDetails();
            ocontacts.Name = Convert.ToString(oYahooContacts.ContactName);
            ocontacts.EmailAddress = Convert.ToString(oYahooContacts.Email);
            ContactList.Add(ocontacts);

        }
        return ContactList;
    }
}

public class YahooContacts
    {
        private string contactId;
        private string contactName;
        private string email;


    public string ContactID
    {
        get { return contactId; }
        set { contactId = value; }
    }

    public string ContactName
    {
        get { return contactName; }
        set { contactName = value; }
    }

    public string Email
    {
        get { return email; }
        set { email = value; }
    }
}

Any suggestions?

\$\endgroup\$
6
\$\begingroup\$

These are bad variable names, they should be descriptive of what kind of values they contain:

string[] tmp1 = cookie.Split(',');
string[] tmp2 = var.Split(';');

Moreover, tmp1 isn't even necessary since you only use it once.

Also avoid things like oYahooContacts, just name them yahooContacts.

Don't abbreviate, e.g. _pass. It isn't necessary and only makes code harder to read.


I don't think ParseYahooResponse is descriptive enough. Sure, that method does parse the response, but more importantly it returns a list of contacts.


Variables should be camelCase:

List<ContactDetails> ContactList = new List<ContactDetails>();
List<YahooContacts> Contacts

I don't think YahooContacts is a good class name, for one it is a plural. It can also be simplified by using Auto-Implemented Properties, e.g.

public string ContactID {get;set;}

Things like private const string _addressBookUrl belong in a separate class IMHO, or perhaps in a config file.

Why do you name your parameter _username and then assign it to the variable login? Plus in your test method you call it "UserId".


I'm not a fan of this:

postToLogin.Add(".save", "Sign In");
postToLogin.Add(".persistent", "y");
postToLogin.Add("login", login);
postToLogin.Add("passwd", _pass);

This reeks of magic strings. I would be tempted to make this a class of its own, which then can be converted to a NameValueCollection, and things like ".save" would be constants in that class, perhaps.

At least I'd move the whole postToLogin logic to its own class, have it parse the response and return a NameValueCollection.

Actually, that goes for most of the code. I'd move some code from GetYahooContacts at least to separate methods, certainly the lines where you create a new cookie. The whole method is rather hard to figure out, for instance I didn't quite understand why you assigned to webclient.Headers[HttpRequestHeader.Cookie] multiple times until I noticed webclient.UploadValues(_authUrl, postToLogin); happens between those two assignments.

I'd much prefer it if the logic in that method was distributed over several shorter method, so the logic becomes clearer, e.g. do a download, parse the response/create the postToLogin NameValueCollection, do an upload, create the cookie, do a download, get the contact details.

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

I don't have a whole lot of time right now, but I noticed this while scanning through your code.

      catch (Exception e)
      {
          throw e;
      }

There's no point in catching an exception just to re throw it. This adds unnecessary overhead to the code. You might as well just remove the try...catch block.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.