# tutorial_4.cpp

## C++ Tutorial Step 4: Retrieving contact list and catching online status change events

In this example we will write a program to

- Populate the contact list
- Catch contact online status updates

### Code Walkthrough

The first thing we need to do is retrieve a ContactGroup. In addition to user-defined contact groups, there is a list of "hardwired" contact groups that are automatically populated. You can use these to retrieve subsets of the contact list as needed. The hardwired contact groups are:

- ALL_KNOWN_CONTACTS - Entire contactlist, including non-authorized contacts.
- ALL_BUDDIES - All authorized contacts.
- SKYPE_BUDDIES - All authorized skypename contacts.
- SKYPEOUT_BUDDIES - All PSTN contacts.
- ONLINE_BUDDIES - All authorized skypename contacts currently online.
- UNKNOWN_OR_PENDINGAUTH_BUDDIES - Contacts in my buddylist that have not authorized me yet.
- RECENTLY_CONTACTED_CONTACTS - Contacts I've had recent conversations with (incl. non-buddies).
- CONTACTS_WAITING_MY_AUTHORIZATION - Contacts to whose auth request I've not responded yet.
- CONTACTS_AUTHORIZED_BY_ME - All contacts that I have authorized (incl. non-buddies).
- CONTACTS_BLOCKED_BY_ME - All contacts that I have blocked (incl. non-buddies).
- UNGROUPED_BUDDIES - All buddies that do not belong to any custom group.
- CUSTOM_GROUP - Custom group.
- EXTERNAL_CONTACTS - Contacts from external address book(s).

To retrieve a contact group, we will use the Skype::GetHardwiredContactGroup method. For purposes of this example, let's use SKYPE_BUDDIES as our filter, as in case non-SKYPE_BUDDIES the online status does not have a meaning anyway.

    MyContactGroup::Ref skypeNamesContactGroup;
    skype->GetHardwiredContactGroup(ContactGroup::SKYPE_BUDDIES, skypeNamesContactGroup);

This returned us a reference to a contact group. Note that the contact group itself does not directly give us access to any Contact objects. We need an additional step to get to the reference list of contacts.

    ContactRefs contactList;
    skypeNamesContactGroup->GetContacts(contactList);
    fetch(contactList);

This will give us a list of all Contact objects from the SKYPE_BUDDIES group in wrapper cache, so that we get event and property updates for them.

For the second part of this exercise, catching status changes, we'll catch the Contact::OnChange event. For this we will need to derive our own class:

    class MyContact : public Contact
    {
    public:
      typedef DRef<MyContact, Contact> Ref;
      typedef DRefs<MyContact, Contact> Refs;
      MyContact(unsigned int oid, SERootObject* root) : Contact(oid, root) {};

      void OnChange(int prop);
    };

Contact online status is in P_AVAILABILITY property, so the implementation of the OnChange would like this:

    void MyContact::OnChange(int prop)
    {
      if (prop == Contact::P_AVAILABILITY)
      {
        SEString name;
        GetPropDisplayname(name);

        Contact::AVAILABILITY availability;
        GetPropAvailability(availability);

        SEString statusAsText;
        statusAsText = tostring(availability);

        printf("%s -> %s\n", (const char*)name, (const char*)statusAsText);
      };
    };

The output produced from this should look more or less like this:

    test contact 1 -> Contact::AVAILABILITY.AWAY
    test contact 2 -> Contact::AVAILABILITY.AWAY
    test contact 3 -> Contact::AVAILABILITY.ONLINE

Normally, this would be it - except that the above code is not 100% reliable. Firstly, in case of full client UI, the user could add and/or authorize more skype contacts.

Secondly, there is the case of logging in first time on a clean local database, with an account that has contacts added already (on other machines). In this case, immediately after login, the GetHardwiredContactGroup will return an empty list - as the virgin local database is empty. Old contacts will be synced in over time - during the CBL (Central Buddy List) synchronization phase that takes place after login.

In both these cases, we need to check for new arrivals to our SKYPE_BUDDIES ContactGroup and get a live reference to the contact object that was added.

For this we will need to write our own ContactGroup class, to maintain the list of contacts.

    class MyContactGroup : public ContactGroup
    {
    public:
      typedef DRef<MyContactGroup, ContactGroup> Ref;
      typedef DRefs<MyContactGroup, ContactGroup> Refs;
      MyContactGroup(unsigned int oid, SERootObject* root) : ContactGroup(oid, root) {};

      MyContact::Refs contactList;
      virtual void OnChange( const ContactRef& contact );
    };

    void MyContactGroup::OnChange(const ContactRef& contact)
    {
      ContactGroup::TYPE groupType;
      this->GetPropType(groupType);

      if (groupType == ContactGroup::SKYPE_BUDDIES)
      {
        SEString contactName;
        contact->GetPropDisplayname(contactName);

        if (!contactList.contains(contact))
        {
          contactList.append(contact);
          contact.fetch();
          printf("%s was added.\n", (const char*)contactName);
        }
        else
        {
          contactList.remove_val(contact);
          printf("%s was removed.\n", (const char*)contactName);
        };
      };
    };

## Full code of this example

    /****************************************************************************

    Getting Started With SkypeKit. Tutorial Application, Step 4.

    In this example we will write a program to

     1. Populate the contact list
     2. Catch contact online status updates

    **/

    #include "skype-embedded_2.h"
    #include "keypair.h"
    #include "tutorial_common.h"

    using namespace Sid;

    SEString myAccountName;
    SEString myAccountPsw;

    //----------------------------------------------------------------------------
    // Interface section

    class MyContact : public Contact
    {
    public:
      typedef DRef<MyContact, Contact> Ref;
      typedef DRefs<MyContact, Contact> Refs;
      MyContact(unsigned int oid, SERootObject* root) : Contact(oid, root) {};

      void OnChange(int prop);
    };

    //----------------------------------------------------------------------------
    // Overrideing contact group class here, to handle cases when this tutorial is used to
    // log in with an already existing account first time on a local system. In this case
    // the contact list starts out empty - as the local database for account was just created.
    // The contact list will then build itself up during CBL synchronization. To obtain
    // references to these newly synchronized contacts, it is necessary to catch
    // ContactGroup's OnChange event and add/remove references to our live reference list.

    class MyContactGroup : public ContactGroup
    {
    public:
      typedef DRef<MyContactGroup, ContactGroup> Ref;
      typedef DRefs<MyContactGroup, ContactGroup> Refs;
      MyContactGroup(unsigned int oid, SERootObject* root) : ContactGroup(oid, root) {};

      MyContact::Refs contactList;
      virtual void OnChange( const ContactRef& contact );
    };

    class MySkype : public Skype
    {
    public:
      MySkype() : Skype() {};

      Account*      newAccount(int oid) {return new MyAccount(oid, this);}
      ContactGroup* newContactGroup(int oid) {return new MyContactGroup(oid, this);}
      Contact*      newContact(int oid) {return new MyContact(oid, this);}
    };

    //----------------------------------------------------------------------------
    // Implementation section

    void MyContact::OnChange(int prop)
    {
      if (prop == Contact::P_AVAILABILITY)
      {
        SEString name;
        GetPropDisplayname(name);

        Contact::AVAILABILITY availability;
        GetPropAvailability(availability);

        SEString statusAsText;
        statusAsText = tostring(availability);

        printf("%s -> %s\n", (const char*)name, (const char*)statusAsText);
      };
    };

    void MyContactGroup::OnChange(const ContactRef& contact)
    {
      ContactGroup::TYPE groupType;
      this->GetPropType(groupType);

      if (groupType == ContactGroup::SKYPE_BUDDIES)
      {
        SEString contactName;
        contact->GetPropDisplayname(contactName);

        if (!contactList.contains(contact))
        {
          contactList.append(contact);
          contact.fetch();
          printf("%s was added.\n", (const char*)contactName);
        }
        else
        {
          contactList.remove_val(contact);
          printf("%s was removed.\n", (const char*)contactName);
        };
      };
    };

    //----------------------------------------------------------------------------
    // Main

    MySkype* skype = 0;

    int main(int argc, char * argv[])
    {
      printf("*****************************************************************\n");
      printf(" SkypeKit Tutorial, Step 4. - Contacts and online status events.\n");
      printf("*****************************************************************\n");

      if (argc < 3)
      {
        printf("usage: tutorial_4 <skypename> <password>\n");
        return 0;
      };

      myAccountName   = argv[1];
      myAccountPsw    = argv[2];

      printf("Creating skype ..\n");
      skype = new MySkype();

      printf("Submitting application token..\n");
      getKeyPair ();
      skype->init(keyBuf, inetAddr, portNum, "streamlog.txt");
      skype->start();

      printf("Retrieving account ..\n");
      MyAccount::Ref account;

      if (skype->GetAccount(myAccountName, account))
      {
        printf("Logging in..\n");
        account->LoginWithPassword(myAccountPsw, false, true);
        account->BlockWhileLoggingIn();

        if (account->loggedIn)
        {
          printf("Loggin complete.\n");

          MyContactGroup::Ref skypeNamesContactGroup;
          skype->GetHardwiredContactGroup(ContactGroup::SKYPE_BUDDIES, skypeNamesContactGroup);

          skypeNamesContactGroup->GetContacts(skypeNamesContactGroup->contactList);
          fetch(skypeNamesContactGroup->contactList);

          for (uint i = 0; i < skypeNamesContactGroup->contactList.size(); i++)
          {
            SEString contactName;
            skypeNamesContactGroup->contactList[i]->GetPropDisplayname(contactName);
            printf("%3d. %s\n", i+1, (const char*)contactName);
          };

          printf("Waiting for contact status change events..\n");
          printf("Press ENTER to quit.\n");
          getchar();
          printf("Logging out..\n");
          account->Logout(false);
          account->BlockWhileLoggingOut();
          printf("Logout complete.\n");
        };
      }
      else
      {
        printf("Account does not exist\n");
      };

      printf("Cleaning up.\n");
      skype->stop();
      delete skype;
      printf("Done.\n");
      return 0;
    };

All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

(c) Skype Technologies S.A. Confidential/Proprietary

Last updated: Fri Mar 16 2012