The first step is to #include the necessary AIM Developer SDK header files. For Windows, we can also insert #pragmas to bring in the necessary library files for the linker. We also reference AccSupport.h since we will be using the helper classes in that header file.
#include <stdio.h> // printf
#include "AccCore.h" // AIMCC main header
#include "AccSupport.h" // AIMCC C++ helper classes
#ifdef _MSC_VER
#pragma comment(lib, "acccore.lib") // aimcc main lib
#pragma comment(lib, "accuuidlib.lib") // aimcc uuid lib
#endif
Next, we create a class
for our application. We do this because we need a class to implement the
callback interface in order to receive events. Since we are using
AccSupport.h, we derive our class from CAccEventSink. We also define Init,
Run, and Term methods in our class, and call them in from our main()
function. Note that this is only an implementation technique and is not
required.
class CSampleApp : public CAccEventSink
{
public:
HRESULT Init(const char* userName, const char* password)
{
return E_NOTIMPL;
}
HRESULT Run()
{
return E_NOTIMPL;
}
void Term()
{
}
};
int main(int argc, char* argv[])
{
// check args
if (argc != 3)
{
printf("usage: accsample username password\n");
return -1;
}
// create the app object and sign on
CAccPtr<CSampleApp> sp(new CSampleApp);
HRESULT hr = (sp) ? sp->Init(argv[1], argv[2]) : E_OUTOFMEMORY;
if (FAILED(hr))
{
printf("initialization error, hr=%08X\n", hr);
return (int)hr;
}
// run the message loop
hr = sp->Run();
sp->Term();
return (int)hr;
}
Now, we add a call to the
AIM global API function AccCreateSession to create an IAccSession interface,
the primary interface in the AIM Developer SDK. We store the result of this
operation in a CAccPtr smart pointer. This pointer will automatically
Release the IAccSession interface when the smart pointer is destroyed. We
also add calls to Advise and Unadvise to connect and disconnect our callback
interface with the IAccSession interface, as well as an AccMessageLoop call
to spin our event loop while our client runs.
HRESULT Init(const char* userName, const char* password)
{
HRESULT hr;
if (SUCCEEDED(hr = AccCreateSession(IID_IAccSession, (void**)&m_sp)) &&
SUCCEEDED(hr = Advise(m_sp)))
{
}
return hr;
}
HRESULT Run()
{
return AccMessageLoop();
}
void Term()
{
Unadvise(m_sp);
m_sp = NULL;
}
private:
CAccPtr<IAccSession> m_sp;
The next step is to
initialize the IAccSession interface and invoke the SignOn method so that
our client connects to the AIM service. We must do three things here:
identify our client to the AIM network by filling in the
AccClientInfoProp_Description
property on the IAccClientInfo interface, specify the screenname we want to
use by setting the Identity property on the IAccSession interface, and
finally call IAccSession::SignOn with the password. Note that we specify our AIM Custom
Client key in our description string.
HRESULT Init(const char* userName, const char* password)
{
// 1. create aimcc main object, hook up for events
// 2. set information to identify this client
// 3. specify username and password, and sign on
HRESULT hr;
if (SUCCEEDED(hr = AccCreateSession(IID_IAccSession, (void**)&m_sp)) &&
SUCCEEDED(hr = Advise(m_sp)))
{
CAccPtr<IAccClientInfo> spClientInfo;
hr = m_sp->get_ClientInfo(&spClientInfo);
if (SUCCEEDED(hr))
{
CAccVariant desc(L"accsample (key=ju13LC0KMdgmkiO0)");
spClientInfo->put_Property(AccClientInfoProp_Description, desc);
if (SUCCEEDED(hr = m_sp->put_Identity(CAccBstr(userName))))
hr = m_sp->SignOn(CAccBstr(password));
}
}
return hr;
}
Now our client can sign on
to the AIM network. However, we don't get much feedback about how things are
going. So we will add an override for the OnStateChange callback, which is
called as our SignOn attempt proceeds and ultimately succeeds or fails. We
will print out the current session state when each callback is received, and
if we go offline, we will post a quit message to stop the message pump
(which will cause AccMessageLoop to return and the app to exit).
void OnStateChange(
IAccSession* piSession, AccSessionState state, AccResult hr)
{
// quit when we go offline
printf("state change: state=%d, hr=%08X\n", state, hr);
if (state == AccSessionState_Offline)
AccPostQuit(hr);
}
Things are starting to get
interesting. The next step is to process incoming IM sessions so that we can
interact with our application from another AIM client. We will tell our
client to automatically accept incoming IM sessions, and if we receive an IM
that consists of the message "quit", we will sign out of the AIM service. We
do this by calling IAccSecondarySession::Accept when we are prompted to
decide on the disposition of incoming IM sessions, by calling IAccIm::GetConvertedText on the IM when it arrives to get it in plaintext
format, and finally IAccSession::SignOff when we decide to sign out. Note
that we use the CAccBstr helper class to automatically dispose of the
returned string pointer.
void OnSecondarySessionStateChange(
IAccSession* piSession, IAccSecondarySession* piSecSession,
AccSecondarySessionState state, AccResult hr)
{
// always accept incoming IM sessions
if (state == AccSecondarySessionState_ReceivedProposal)
{
AccSecondarySessionServiceId id;
piSecSession->get_ServiceId(&id);
if (id == AccSecondarySessionServiceId_Im)
piSecSession->Accept();
}
}
void OnImReceived(
IAccSession* piSession, IAccImSession* piImSession,
IAccParticipant* piSender, IAccIm* piIm)
{
// signoff when we get an IM that says "quit"
CAccBstr text;
piIm->GetConvertedText(OLESTR("text/plain"), &text);
if (text == OLESTR("quit"))
m_sp->SignOff();
}
Now we have an (albeit minimal) AIM Custom Client that can sign into the AIM network, receive IMs, and sign out. The full code is shown below. This code is also included in the SDK under samples/clients/accsample. For a more full-featured (but more complex) client, see the "amfcbuddy" sample under samples/clients/amfcbuddy,
///----------------------------------------------------------------------------
///
/// File Name: accsample.cpp
/// Copyright (c) 2005-2006 America Online, Inc. All rights reserved.
///
///----------------------------------------------------------------------------
#include <stdio.h> // printf
#include "AccCore.h" // AIMCC main header
#include "AccSupport.h" // AIMCC C++ helper classes
#ifdef _MSC_VER
#pragma comment(lib, "acccore.lib") // aimcc main lib
#pragma comment(lib, "accuuidlib.lib") // aimcc uuid lib
#endif
class CSampleApp : public CAccEventSink
{
public:
HRESULT Init(const char* userName, const char* password)
{
// 1. create aimcc main object, hook up for events
// 2. set information to identify this client
// 3. specify username and password, and sign on
HRESULT hr;
if (SUCCEEDED(hr = AccCreateSession(IID_IAccSession, (void**)&m_sp)) &&
SUCCEEDED(hr = Advise(m_sp)))
{
CAccPtr<IAccClientInfo> spClientInfo;
hr = m_sp->get_ClientInfo(&spClientInfo);
if (SUCCEEDED(hr))
{
CAccVariant desc(L"aatlbuddy (key=ju13LC0KMdgmkiO0)");
spClientInfo->put_Property(AccClientInfoProp_Description, desc);
if (SUCCEEDED(hr = m_sp->put_Identity(CAccBstr(userName))))
hr = m_sp->SignOn(CAccBstr(password));
}
}
return hr;
}
HRESULT Run()
{
// run a message loop until AccPostQuit is called
return AccMessageLoop();
}
void Term()
{
// clean up events and aimcc object
Unadvise(m_sp);
m_sp = NULL;
}
void OnStateChange(
IAccSession* piSession, AccSessionState state, AccResult hr)
{
// quit when we go offline
printf("state change: state=%d, hr=%08X\n", state, hr);
if (state == AccSessionState_Offline)
AccPostQuit(hr);
}
void OnSecondarySessionStateChange(
IAccSession* piSession, IAccSecondarySession* piSecSession,
AccSecondarySessionState state, AccResult hr)
{
// always accept incoming IM sessions
if (state == AccSecondarySessionState_ReceivedProposal)
{
AccSecondarySessionServiceId id;
piSecSession->get_ServiceId(&id);
if (id == AccSecondarySessionServiceId_Im)
piSecSession->Accept();
}
}
void OnImReceived(
IAccSession* piSession, IAccImSession* piImSession,
IAccParticipant* piSender, IAccIm* piIm)
{
// signoff when we get an IM that says "quit"
CAccBstr text;
piIm->GetConvertedText(OLESTR("text/plain"), &text);
if (text == OLESTR("quit"))
m_sp->SignOff();
}
private:
CAccPtr<IAccSession> m_sp;
};
int main(int argc, char* argv[])
{
// check args
if (argc != 3)
{
printf("usage: accsample username password\n");
return -1;
}
// create the app object and sign on
CAccPtr<CSampleApp> sp(new CSampleApp);
HRESULT hr = (sp) ? sp->Init(argv[1], argv[2]) : E_OUTOFMEMORY;
if (FAILED(hr))
{
printf("initialization error, hr=%08X\n", hr);
return (int)hr;
}
// run the message loop
hr = sp->Run();
sp->Term();
return (int)hr;
}
Questions? Visit
http://developer.aim.com/
Last updated:
03/03/2006