tutorial_12.cpp

C++ Tutorial Step 12: Event history

All events, such as live sessions, voicemails, SMS messages, file transfers, etc. are reflected in the SkypeKit API as Message objects. In order to retrieve a historic list of certain type of events, you will need to obtain a list of corresponding messages.

As of SDK version 4.0, the SkypeKit API includes a much better way of doing this - Skype::GetMessageListByType

This method enables you to retrieve messages of certain Message::TYPE accross all conversations. For example, to retrieve a "global" list of file transfers, you could use skype->GetMessageListByType(Message::POSTED_FILES, false, history, fromTime, toTime) and you would end up with all the file transfer related messages in the given time period, neatly in the history argument.

The only problem then is that most of the relevant info you might want to display in your UI, for each of those Message objects, is encoded in the type-specific Message::P_BODY_XML property.

In this exercise, we will look into how this can be done for:

Full code of this example

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

Getting Started With SkypeKit. Tutorial Application, Step 12.

In this exercise, we will assemble an event history, of:
1. Incoming calls
2. Outgoing calls
3. Authorization request
4. Authorizations granted

**/

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

using namespace Sid;

SEString myAccountName;
SEString myAccountPsw;

//----------------------------------------------------------------------------
// Subclassing Contact

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

//----------------------------------------------------------------------------
// Subclassing Skype

class MySkype : public Skype
{
public:
  MySkype() : Skype() {};
  Account* newAccount(int oid) { return new MyAccount(oid, this); };
  Contact* newContact(int oid) { return new MyContact(oid, this); };
};

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

MySkype* skype;

int main(int argc, char * argv[])
{
  printf("*****************************************************************\n");
  printf(" SkypeKit Tutorial, Step 12 - Event History.\n");
  printf("*****************************************************************\n");

  if (argc < 3)
  {
    printf("usage: tutorial <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();
    printf("Loggin complete.\n");

    Conversation::Refs conversationList;
    skype->GetConversationList(conversationList);
    for (uint i = 0; i < conversationList.size(); i++)
    {
      Message::Refs contextMessages;
      Message::Refs unconsumedMessages;
      // Replace '0' with real timestamp to get more.
      conversationList[i]->GetLastMessages(contextMessages, unconsumedMessages, 0);

      for (int k = 0; k < 2; k++)
      {
        Message::Refs loopref;              
        loopref = (k)?contextMessages:unconsumedMessages;
        int messageRefsCount=loopref.size();

        for (int j = 0; j < messageRefsCount; j++)
        {
          Message::TYPE msgType=(Message::TYPE)atoi((const char*)(loopref[j]->GetProp(Message::P_TYPE)));
          switch (msgType)
          {
            case Message::STARTED_LIVESESSION:
            {
              // Message::P_AUTHOR tells who initiated the call.
              SEString author=loopref[j]->GetProp(Message::P_AUTHOR);

              // For duration we unfortunately have to parse the XML
              // the duration that interests me is in
              // <part identity="&me">\n<duration>x</duration>...
              //
              // Real implementation should use a proper xml-parser here
              SEString body=loopref[j]->GetProp(Message::P_BODY_XML);
              const char *body_str=(const char*)body;
              char partname[256];
              snprintf(partname,256,"<part identity=\"%s\">",(const char*)myAccountName);
              const char *my_part=strstr(body_str,partname);
              int duration=-1;
              if (my_part)
              {
                const char *my_part_end=strstr(my_part,"</part>");
                if (my_part_end)
                {
                  const char *duration_str=strstr(my_part,"<duration>");
                  if (duration_str && duration_str<my_part_end)
                  {
                    duration_str+=strlen("<duration>");
                    duration=atoi(duration_str);
                  }
                }
              }
              // ditto for counting how many parts the body has.
              int num_parts=0;
              char *tmp=(char*)body_str;
              while ((tmp=strstr(tmp,"<part")))
              {
                tmp++;
                num_parts++;
              }
              // get identities
              SEString identities=loopref[j]->GetProp(Message::P_IDENTITIES);
              // timestamp
              time_t timestamp=loopref[j]->GetUintProp(Message::P_TIMESTAMP);
              char *time_str=ctime(&timestamp);
              time_str[24]=0; // remove newline
              // last part is to fetch message reason
              SEString reason=loopref[j]->GetProp(Message::P_REASON);

              printf("[%s] ",time_str);
              if (!strcmp((const char*)author,(const char*)myAccountName))
              {
                // I was the initiator
                printf("outgoing call to %s: ",(const char*)identities);
              } else {
                // somebody else called
                printf("incoming call from %s: ",(const char*)identities);
              }
              if (duration>=0)
              {
                printf("duration %d seconds\n",duration);
              } 
              else 
              {
                if (num_parts>1)
                {
                  if (!strcmp((const char*)reason,"manual"))
                  {
                    printf("refused\n");
                  } else {
                    printf("failed (%s)\n",(const char*)reason);
                  }
                }
                else 
                {
                  printf("missed\n");
                }
              }
            }
            break;

            case Message::POSTED_VOICE_MESSAGE:
            {
              SEString author=loopref[j]->GetProp(Message::P_AUTHOR);
              // XML parsing again...
              SEString body=loopref[j]->GetProp(Message::P_BODY_XML);
              const char *body_str=(const char*)body;
              int length=0;
              const char *len_str=strstr(body_str,"<length>");
              if (len_str)
              {
                len_str+=strlen("<length>");
                length=atoi(len_str);
              }
              // get identities
              SEString identities=loopref[j]->GetProp(Message::P_IDENTITIES);
              // timestamp
              time_t timestamp=loopref[j]->GetUintProp(Message::P_TIMESTAMP);
              char *time_str=ctime(&timestamp);
              time_str[24]=0; // remove newline
              printf("[%s] ",time_str);
              if (!strcmp((const char*)author,(const char*)myAccountName))
              {
                // I was the initiator
                printf("Sent voicemail to %s: ",(const char*)identities);
              } 
              else 
              {
                // somebody else called
                printf("Got voicemail from %s: ",(const char*)identities);
              }
              printf("duration %d\n",length);
            }
            break;

            case Message::REQUESTED_AUTH:
            // Please note that REQUESTED_AUTH is not used to request authorization
            // ALERT is used for that. REQUESTED_AUTH is used only for history
            {
              SEString author=loopref[j]->GetProp(Message::P_AUTHOR);
              // get identities
              SEString identities=loopref[j]->GetProp(Message::P_IDENTITIES);
              // timestamp
              time_t timestamp=loopref[j]->GetUintProp(Message::P_TIMESTAMP);
              char *time_str=ctime(&timestamp);
              time_str[24]=0; // remove newline
              printf("[%s] ",time_str);
              printf("Authorization request from %s to %s\n",(const char*)author,(const char*)identities);
            }
            break;

            case Message::GRANTED_AUTH:
            {
              SEString author=loopref[j]->GetProp(Message::P_AUTHOR);
              // get identities
              SEString identities=loopref[j]->GetProp(Message::P_IDENTITIES);
              // timestamp
              time_t timestamp=loopref[j]->GetUintProp(Message::P_TIMESTAMP);
              char *time_str=ctime(&timestamp);
              time_str[24]=0; // remove newline
              printf("[%s] ",time_str);
              printf("%s granted authorization to %s\n",(const char*)author,(const char*)identities);
            }
            break;

            default:
            break;
          }
        }
      }
    }

    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