Greg's Mind Code Samples
Custom Client Code

View avTestor Code - This code will show you how to build your own AIM client with audio video built in via C-Sharp.

using System;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;
using AccCoreLib;
using RTCCORELib;

namespace AvTestor
{
	class AvTestor : Control
	{
		[DllImport("acccore.dll", EntryPoint="#111", PreserveSig=false)] 
		private static extern void AccCreateSession(
			[MarshalAs(UnmanagedType.LPStruct)] Guid riid,
			[MarshalAs(UnmanagedType.IDispatch)] out object session);				
		private static AvTestor avTest;
		private AccSession s;
		private IAccAvManager m_avManager;
		private IAccAvSession m_avSession;
		private IVideoWindow  m_remoteVideo;

		[STAThread]
		static void Main(string[] args)
		{
			if (args.Length != 2)
			{
				Console.WriteLine("usage: acshbuddy screenname password");
				return;
			}
			
			avTest = new AvTestor();
			avTest.Run(args[0], args[1]);
		}

		private void Run(string username, string password)
		{
			try 
			{				
				// create control to allow invokes
				CreateControl();	
				
				// create and init session
				object o;
				AccCreateSession(typeof(IAccSession).GUID, out o);				
				s = (AccSession)o;
				s.ClientInfo.set_Property(AccClientInfoProp.AccClientInfoProp_Description,
					"acshbuddy (key=ju1yztKT86VJ0xj3)");
				s.Identity = username;
				s.SignOn(password);	
			
				// event list
				s.OnStateChange += new DAccEvents_OnStateChangeEventHandler(s_OnStateChange);
				s.OnSecondarySessionStateChange += new DAccEvents_OnSecondarySessionStateChangeEventHandler(s_OnSecondarySessionStateChange);
				s.OnAudioLevelChange += new DAccEvents_OnAudioLevelChangeEventHandler(s_OnAudioLevelChange);
				s.OnAvManagerChange += new DAccEvents_OnAvManagerChangeEventHandler(s_OnAvManagerChange);
				s.OnAvStreamStateChange += new DAccEvents_OnAvStreamStateChangeEventHandler(s_OnAvStreamStateChange);
				s.OnInviteResult += new DAccEvents_OnInviteResultEventHandler(s_OnInviteResult);
				s.OnParticipantJoined += new DAccEvents_OnParticipantJoinedEventHandler(s_OnParticipantJoined);
				s.OnParticipantLeft += new DAccEvents_OnParticipantLeftEventHandler(s_OnParticipantLeft);

				// start main loop
				Application.Run();				
			}
			catch (COMException e)
			{
				Console.WriteLine(e.Message);
			}
		}

		// class functions to handle AV stuff
		private void QuitAvSession()
		{
			try
			{
				if (m_avSession != null)
				{
					bool isVideo = (bool)m_avSession.get_Property((int)AccAvSessionProp.AccAvSessionProp_Video);
					if (isVideo && m_remoteVideo != null)
					{
						Console.WriteLine("Start closing the Video Window and releasing the object");
						m_remoteVideo.Visible = 0;
						m_remoteVideo = null;
						Console.WriteLine("Finished closing the Video Window and releasing the object");
					}

					Console.WriteLine("Local side is quiting the AvSession");
					IAccSecondarySession secSession = (IAccSecondarySession)m_avSession;
					object o = secSession.get_Property((int)AccSecondarySessionProp.AccSecondarySessionProp_State);
					AccSecondarySessionState state = (AccSecondarySessionState)o;
					if (state != AccSecondarySessionState.AccSecondarySessionState_Offline)
						m_avSession.EndSession();
					m_avSession = null;
				}
				Console.WriteLine("Starting garbage collection");
				GC.Collect();
				GC.WaitForPendingFinalizers();			
				Console.WriteLine("Garbage collection complete");
			}
			catch (COMException e)
			{
				Console.WriteLine(e.Message);
			}

		}

		private void StartAvSession(string userName, int flags)
		{
			try
			{
				if (m_avManager == null)
					m_avManager = (IAccAvManager)s.GetSecondaryManager((int)AccSecondarySessionServiceId.AccSecondarySessionServiceId_AudioVideo);
				m_avSession = m_avManager.CreateSession(userName, flags);
				if (flags == (int)AccAvFlags.AccAvFlags_Video)
					Console.WriteLine("Creating Video Session with {0}.", userName);
				else
					Console.WriteLine("Creating Audio Session with {0}.", userName);
			}
			catch (COMException e)
			{
				Console.WriteLine(e.Message);
			}
		}

		private void QuitAvTestor()
		{
			if (m_avSession != null)
			{
				bool isVideo = (bool)m_avSession.get_Property((int)AccAvSessionProp.AccAvSessionProp_Video);
				if (isVideo && m_remoteVideo != null)
				{
					Console.WriteLine("Start closing the Video Window and releasing the object");
					m_remoteVideo.Visible = 0;
					m_remoteVideo = null;
					Console.WriteLine("Finished closing the Video Window and releasing the object");
				}
				IAccSecondarySession secSession = (IAccSecondarySession)m_avSession;
				object o = secSession.get_Property((int)AccSecondarySessionProp.AccSecondarySessionProp_State);
				AccSecondarySessionState state = (AccSecondarySessionState)o;
				if (state != AccSecondarySessionState.AccSecondarySessionState_Offline)
					m_avSession.EndSession();
				m_avSession = null;
			}

			m_avManager = null;
			s.SignOff();
			Console.WriteLine("Starting garbage collection");
			GC.Collect();
			GC.WaitForPendingFinalizers();			
			Console.WriteLine("Garbage collection complete");
			Application.Exit();	
		}

		private void StartMultiPartyAvSession(string roomName, int flags)
		{
			try
			{
				m_avSession = m_avManager.CreateMultipartySession(roomName, flags);
				Console.WriteLine("Creating Multiparty Session with roomName {0}.", roomName);
			}
			catch (COMException e)
			{
				Console.WriteLine(e.Message);
			}
		}

		private void InviteBuddyToSession(string userName)
		{
			if (m_avSession == null)
			{
				Console.WriteLine("Start a Multiparty Session before trying to invite someone.");
				return;
			}

			try
			{
				IAccSecondarySession secSession = (IAccSecondarySession)m_avSession;
				object o = secSession.get_Property((int)AccSecondarySessionProp.AccSecondarySessionProp_State);
				AccSecondarySessionState state = (AccSecondarySessionState)o;
				if (state != AccSecondarySessionState.AccSecondarySessionState_Online)
				{
					Console.WriteLine("Only invite a user once the Multiparty Session is online, right now the state is {0}.", state);
					return;
				}

				m_avSession.Invite(userName, "Please join me in this audio session");
			}
			catch (COMException e)
			{
				Console.WriteLine(e.Message);
			}
		}

		private void ListUsersInSession()
		{
			try
			{
				if (m_avSession == null)
				{
					Console.WriteLine("Cannot list users without a session");
					return;
				}
				Array a = (Array) m_avSession.get_Property((int)AccSecondarySessionProp.AccSecondarySessionProp_Participants);
				IAccParticipant[] attendees = new IAccParticipant[a.Length];
				Console.WriteLine("Start reading the participant array, array contains {0} items.", a.Length);
				foreach ( IAccParticipant user in a )
				{
					Console.WriteLine("Participant : {0}", user.Name);
				}
				Console.WriteLine("Finished reading the participant array, array contained {0} items.", a.Length);
			}
			catch (COMException e)
			{
				Console.WriteLine(e.Message);
			}
		}

		
		private void DumpAvManager()
		{
			// input devices
			Array a =(Array)m_avManager.get_Property(AccAvManagerProp.AccAvManagerProp_AvailableInputDevices);
			string[] inDevice = new string[a.Length];
			Console.WriteLine("Available InPutDevices...");
			foreach (string str in a)
			{
				Console.WriteLine("InPutDevice : {0}", str);
			}

			// output devices
			Array a2 =(Array)m_avManager.get_Property(AccAvManagerProp.AccAvManagerProp_AvailableOutputDevices);
			string[] outDevice = new string[a2.Length];
			Console.WriteLine("Available OutPutDevices...");
			foreach (string str in a2)
			{
				Console.WriteLine("OutPutDevices : {0}", str);
			}

			// video devices
			Array a3 =(Array)m_avManager.get_Property(AccAvManagerProp.AccAvManagerProp_AvailableVideoInputDevices);
			string[] vidDevice = new string[a3.Length];
			Console.WriteLine("Available VideoDevices...");
			foreach (string str in a3)
			{
				Console.WriteLine("VideoDevices : {0}", str);
			}

			// echo cancelation
			Console.WriteLine("Echo Cancelation is {0}", (bool)m_avManager.get_Property(AccAvManagerProp.AccAvManagerProp_EchoCancellation));

			// input device
			Console.WriteLine("Default Input device is {0}", (string)m_avManager.get_Property(AccAvManagerProp.AccAvManagerProp_InputDevice));

			// library name
			Console.WriteLine("Library name is {0}", (string)m_avManager.get_Property(AccAvManagerProp.AccAvManagerProp_LibraryName));

			// library version
			Console.WriteLine("Library Version is {0}", (UInt32)m_avManager.get_Property(AccAvManagerProp.AccAvManagerProp_LibraryVersion));		

			// max bitrate
			Console.WriteLine("Max Bitrate is {0}", (Int32)m_avManager.get_Property(AccAvManagerProp.AccAvManagerProp_MaxBitrate));		

			// output device
			Console.WriteLine("Default Output device is {0}", (string)m_avManager.get_Property(AccAvManagerProp.AccAvManagerProp_OutputDevice));		

			// video device
			Console.WriteLine("Default Video device is {0}", (string)m_avManager.get_Property(AccAvManagerProp.AccAvManagerProp_VideoInputDevice));				

			// Windows Audio Input device
			Console.WriteLine("Default Windows Audio Input device is {0}", (string)m_avManager.get_Property(AccAvManagerProp.AccAvManagerProp_WindowsAudioInputDevice));		

			// Windows Audio Output device
			Console.WriteLine("Default Windows Audio Output device is {0}", (string)m_avManager.get_Property(AccAvManagerProp.AccAvManagerProp_WindowsAudioOutputDevice));		

			// Windows Voice Input device
			Console.WriteLine("Default Windows Voice Input device is {0}", (string)m_avManager.get_Property(AccAvManagerProp.AccAvManagerProp_WindowsVoiceInputDevice));		

			// Windows Voice Output device
			Console.WriteLine("Default Windows Voice Output device is {0}", (string)m_avManager.get_Property(AccAvManagerProp.AccAvManagerProp_WindowsVoiceOutputDevice));
		}

		private void ShowVideoWindow(string userName)
		{
			m_remoteVideo = (IVideoWindow)m_avSession.GetVideoWindow(userName);
			m_remoteVideo.Visible = -1;
			return;
		}
		
		private void LoadAvManager()
		{
			try
			{
				if (m_avManager == null)
					m_avManager = (IAccAvManager)s.GetSecondaryManager((int)AccSecondarySessionServiceId.AccSecondarySessionServiceId_AudioVideo);
			}
			catch (COMException e)
			{
				Console.WriteLine(e.Message);
			}

		}

		// IM Events to handle AV
		private void s_OnStateChange(AccSession session, AccSessionState State, AccResult hr)
		{
			switch (State)
			{
				case AccSessionState.AccSessionState_Online:
					Console.WriteLine("AvTestor is Online...");
					LoadAvManager();
					WaitForCommand();
					break;
				case AccSessionState.AccSessionState_Offline:
					Console.WriteLine("AvTestor is Offline...");
					Application.Exit();
					break;
				case AccSessionState.AccSessionState_Connecting:
					Console.WriteLine("AvTestor is connecting...");	
					break;
				default:
					Console.WriteLine("AvTestor is {0}", State);
					break;
			}
		}

		private void s_OnSecondarySessionStateChange(AccSession session, IAccSecondarySession secondarySession, AccSecondarySessionState State, AccResult hr)
		{
			// only handle av sessions.
			object type = secondarySession.get_Property((int)AccSecondarySessionProp.AccSecondarySessionProp_ServiceId);
			AccSecondarySessionServiceId id = (AccSecondarySessionServiceId)type;
			if (id != AccSecondarySessionServiceId.AccSecondarySessionServiceId_AudioVideo)
				secondarySession.Reject((int)AccResult.ACC_E_USER_NOT_CAPABLE);

			switch (State)
			{
				case AccSecondarySessionState.AccSecondarySessionState_Online:
				{
					Console.WriteLine("AvTestor has a secondary session state online.");
					// if video then we need to show the video window
					bool isVideo = (bool)m_avSession.get_Property((int)AccAvSessionProp.AccAvSessionProp_Video);
					if (isVideo)
						ShowVideoWindow((string)secondarySession.get_Property((int)AccSecondarySessionProp.AccSecondarySessionProp_RemoteUserName));
				}
					break;
				case AccSecondarySessionState.AccSecondarySessionState_Offline:
					QuitAvSession();
					Console.WriteLine("AvTestor has a secondary session state offline.");
					break;
				case AccSecondarySessionState.AccSecondarySessionState_Connecting:
					Console.WriteLine("AvTestor has a secondary session state connecting.");
					break;
				case AccSecondarySessionState.AccSecondarySessionState_Paused:
					Console.WriteLine("AvTestor has a secondary session state paused.");
					break;
				case AccSecondarySessionState.AccSecondarySessionState_ReceivedProposal:
					Console.WriteLine("AvTestor has a secondary session state received proposal.");
					break;
				case AccSecondarySessionState.AccSecondarySessionState_SentProposal:
					Console.WriteLine("AvTestor has a secondary session state sent proposal.");
					break;
			}
		}

		private void s_OnAudioLevelChange(AccSession session, IAccAvSession avSession, string userName, int level)
		{

		}

		private void s_OnAvManagerChange(AccSession session, IAccAvManager avManager, AccAvManagerProp prop, AccResult hr)
		{
			Console.WriteLine("{0} has changed in the av manager with result {1}.", prop, hr);
		}

		private void s_OnAvStreamStateChange(AccSession session, IAccAvSession avSession, string userName, AccAvStreamType stream, AccSecondarySessionState State, AccResult hr)
		{

		}

		private void s_OnInviteResult(AccSession session, IAccSecondarySession secondarySession, string userName, int transId, AccResult hr)
		{
			Console.WriteLine("The invite to {0} has a result of {1}.", userName, hr);
		}

		private void s_OnParticipantJoined(AccSession session, IAccSecondarySession secondarySession, IAccParticipant participant)
		{
			Console.WriteLine("{0} has joined the av session.", participant.Name);
		}

		private void s_OnParticipantLeft(AccSession session, IAccSecondarySession secondarySession, IAccParticipant participant, AccResult method, string by, string reason)
		{
			Console.WriteLine("{0} has left the av session with method, {1}, by {2}, for reason {3}.", participant.Name, 
				method, by, reason);
		}

		
		// input handler class
		class InputEvent : System.EventArgs
		{
			public InputEvent(string incommand) { command = incommand; }
			public string Command { get { return command; } }
			private readonly string command;
		};
		private delegate void InputHandler(object o, InputEvent e);

		private void WaitForCommand()
		{			
			MethodInvoker mi = new MethodInvoker(GetCommand);
			mi.BeginInvoke(null, null);
		}

		private void GetCommand()
		{								
			string command = Console.ReadLine(); 
			InputEvent e = new InputEvent(command);
			object[] list = { this, e };						
			BeginInvoke(new InputHandler(HandleCommand), list);												
		}

		private void HandleCommand(object o, InputEvent e)
		{			
			string[] tokens = e.Command.Split(' ');
			string verb = tokens[0];			

			switch (verb)
			{
				case ":q":
					QuitAvTestor();
					break;
				case "av:sa":
					if (tokens.Length != 2)
					{
						Console.WriteLine("Usage...  av:sa buddy");
						break;
					}
					StartAvSession(tokens[1], 0);
					break;
				case "av:sv":
					if (tokens.Length != 2)
					{
						Console.WriteLine("Usage...  av:sv buddy");
						break;
					}
					StartAvSession(tokens[1], (int)AccAvFlags.AccAvFlags_Video);
					break;
				case "av:sm":
					if (tokens.Length != 2)
					{
						Console.WriteLine("Usage...  av:sm sessionName");
						break;
					}
					StartMultiPartyAvSession(tokens[1], 0);
					break;
				case "av:i":
					if (tokens.Length != 2)
					{
						Console.WriteLine("Usage...  av:i userName");
						break;
					}
					InviteBuddyToSession(tokens[1]);
					break;
				case "av:lu":
					ListUsersInSession();
					break;
				case "av:dm":
					DumpAvManager();
					break;
				case "av:q":
					QuitAvSession();
					break;
				case "av:l":
					//ListCustomSessions();
					break;
				case ":h":
					Console.WriteLine("av:sa {buddy name}      start audio");
					Console.WriteLine("av:sv {buddy name}      start video");
					Console.WriteLine("av:i  {buddy name}      invite user to a multiparty session");
					Console.WriteLine("av:lu                   list users in a session");
					Console.WriteLine("av:sv {session name}    start multiparty audio");
					Console.WriteLine("av:dm                   dump all the properties from the av manager");
					Console.WriteLine("av:q                    quits the audio or video session");
					Console.WriteLine(":q                      signs off of AIM and quits the test application");
					break;
				case "o:v":
					Console.WriteLine("Client Version: AvTestor 1.0");			
					break;
				default:
					Console.WriteLine("Invalid command");
					Console.WriteLine(":h for list of commands");
					break;
			}
			WaitForCommand();
		}
	}
}
	

Open AIM Bots

View SWA Bot Code - This code will show you how to build your own AIM Bot via C-Sharp.

///----------------------------------------------------------------------------
///
/// File Name: SWAAlertBot.cs
/// Copyright 2007 AOL LLC.  All rights reserved.
///
///----------------------------------------------------------------------------

using System;
using System.Drawing;
using System.Collections;
using System.IO;
using System.Net;
using System.Windows.Forms;
using System.Runtime.InteropServices;

using AccCoreLib;

namespace SWAAlertBot
{
    class SWAAlertBot : Control
	{
        [DllImport("acccore.dll", EntryPoint="#111", PreserveSig=false)] 
        private static extern void AccCreateSession(
            [MarshalAs(UnmanagedType.LPStruct)] Guid riid,
            [MarshalAs(UnmanagedType.IDispatch)] out object session);				
        private static SWAAlertBot a;
        private AccSession s;		
        private System.Timers.Timer t;	
		private ArrayList m_subList;
        
        //global strings
        const string kSubscribe = "subscribe";
        const string kUnSub = "You have been removed from the bot list.  Thanks for using SWAAlerter!";
        const string kSub = "You have successfully subscribed to this bot!  You can always check the bot status by sending \"status\" to the bot.";
        const string kHelpIm = "To subscribe to Southwest Airline alerts type \"subscribe\" to SWAAlerter.  To unsubscribe type \"unsubscribe\" to SWAAlerter.";
        const string kHelp = "help";
        const string kStatus = "status";
        const string kStillSearching = "The bot is still searching Southwest for updates.  You will be the first to know when Southwest.com has been updated.";
        const string kUnsubscribe = "unsubscribe";
        const string kQuickParseUrl = "http://www.southwest.com/cgi-bin/airTab?ss=0";
        // this date is a hack for demo purposes
        // for the bot to work as intended
        // as of 1/23/2007 @ 18:00 EST
        // the date actually would be set to 
        // May 10, 2007.
        const string kLookupDate = "May 9, 2007";
        const string kEventUpdate = "{0} has updated their reservation website.  The old date of {1} is no longer being seen by the bot.  
        You should check it out immediately to start saving money.";

        [STAThread]
        static void Main(string[] args)
		{
            if (args.Length != 2)
            {
                Console.WriteLine("usage: acshbuddy screenname password");
                return;
            }
			
            a = new SWAAlertBot();
            a.Run(args[0], args[1]);			
        }

        private void Run(string username, string password)
        {
            try 
            {				
                // create control to allow invokes
                CreateControl();	

                // set timer to check for southwest.com updates every 30 mins
				t = new System.Timers.Timer(300000);
                t.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed);
                t.SynchronizingObject = a;

                // create the list to keep track of who is subscribing
                m_subList = new ArrayList();

                // create and init session
                object o;
                AccCreateSession(typeof(IAccSession).GUID, out o);				
                s = (AccSession)o;
                s.OnStateChange += new DAccEvents_OnStateChangeEventHandler(s_OnStateChange);
                s.OnSecondarySessionStateChange += new DAccEvents_OnSecondarySessionStateChangeEventHandler(s_OnSecondarySessionStateChange);
                s.OnImReceived += new DAccEvents_OnImReceivedEventHandler(s_OnImReceived);

                // add your own bot identity and open aim bot key here
                s.ClientInfo.set_Property(AccClientInfoProp.AccClientInfoProp_Description,
                    "InsertBotNameHere (key=OPENAIM_KEYGOESHERE)");

                // disable idle				
                s.set_Property(AccSessionProp.AccSessionProp_SecondsOfInactivityBeforeIdleState, int.MaxValue);

                // sign on
                s.Identity = username;
                s.SignOn(password);				

                // start main loop
                Application.Run();				

            }
            catch (COMException e)
            {
                Console.WriteLine(e.Message);
            }
        }

        private void s_OnSecondarySessionStateChange(AccSession session, IAccSecondarySession secondarySession, AccSecondarySessionState State, AccResult hr)
        {
            // accept all IMs
            if ((AccSecondarySessionServiceId)secondarySession.get_Property((int)AccSecondarySessionProp.AccSecondarySessionProp_ServiceId) == 
                AccSecondarySessionServiceId.AccSecondarySessionServiceId_Im &&
                State == AccSecondarySessionState.AccSecondarySessionState_ReceivedProposal)
            {
                IAccImSession piImSession = (IAccImSession)secondarySession;
                AccImSessionType type = (AccImSessionType)
                    piImSession.get_Property((int)AccImSessionProp.AccImSessionProp_SessionTypeProposed);
                if (type == AccImSessionType.AccImSessionType_Im)
                    piImSession.Accept();
            }
        }
        
        private void s_OnImReceived(AccSession session, IAccImSession imSession, IAccParticipant sender, IAccIm im)
        {
            // based on the text sent to us
            // respond appropriately
            DateTime CurrTime = DateTime.Now;
            string imText = im.GetConvertedText("text/plain");
            imText = imText.ToLower();
            if ((imText.CompareTo(kSubscribe) == 0) || (imText.CompareTo("1") == 0))
            {
                Console.WriteLine("*** Subscribe received from {0} @: {1:G}", sender.Name, CurrTime);                    
                m_subList.Add(sender.Name);
                ReplySub(session, imSession, false);
            }
            else if ((imText.CompareTo(kStatus) == 0) || (imText.CompareTo("2") == 0))
            {
                Console.WriteLine("*** {0} has asked for status @: {1:G}", sender.Name, CurrTime);                    
                ReplyStatus(session, imSession);
            }
            else if ((imText.CompareTo(kUnsubscribe) == 0) || (imText.CompareTo("3") == 0))
            {
                Console.WriteLine("*** UN-Subscribe received from {0} @: {1:G}", sender.Name, CurrTime);                    
                m_subList.Remove(sender.Name);
                ReplySub(session, imSession, true);
            }
            else if ((imText.CompareTo(kHelp) == 0) || (imText.CompareTo("4") == 0))
            {
                Console.WriteLine("*** {0} has asked for help @: {1:G}", sender.Name, CurrTime);                    
                ReplyHelp(session, imSession);
            }
            else
            {
                Console.WriteLine("*** {0} im-d us with unknown data @: {1:G}", sender.Name, CurrTime);                    
                ReplyGarbage(session, imSession);
            }
        }

        // timer event
        private void t_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            UpdateState();
        }

        // note when we are online and start the timer
        private void s_OnStateChange(AccSession session, AccSessionState State, AccResult hr)
        {
            Console.WriteLine("> State change: {0}", State);
            if (State == AccSessionState.AccSessionState_Online)
            {
                UpdateState();
                if (!t.Enabled)
                    t.Start();				
            }
        }

        private void ReplyHelp(IAccSession session, IAccImSession imSession)
        {
            string reply = string.Format("<HTML><BODY>This is the help for the <A HREF={0}>Southwest.com</A> Fare Bot!  To use the bot please do one of send the following:
            <BR>1. <B>{1}</B> - Subscribe to the bot.<BR>2. <B>{2}</B> - Get bot status.<BR>3. <B>{3}</B> - Unsubscribe from the bot.
            </BODY></HTML>", kQuickParseUrl, "SUBSCRIBE", "STAUTS", "UNSUBSCRIBE");

            IAccIm im = session.CreateIm(reply, "text/html");
            imSession.SendIm(im);
        }

        private void ReplyStatus(IAccSession session, IAccImSession imSession)
        {
            IAccIm im = session.CreateIm(kStillSearching, "text/plain");
            imSession.SendIm(im);
        }

        private void ReplySub(IAccSession session, IAccImSession imSession, bool leaving)
        {
            // confirm the join or leave on the subscriber list
            IAccIm im;
            if (leaving)
                im = session.CreateIm(kUnSub, "text/plain");
            else
                im = session.CreateIm(kSub, "text/plain");
            
            imSession.SendIm(im);
        }

        private void ReplyGarbage(IAccSession session, IAccImSession imSession)
        {
            // any unregognizable pattern, respond with the bot's task list
            string reply = string.Format("<HTML><BODY>This is the <A HREF={0}>Southwest.com</A> Fare Bot!  To use the bot please do one of the following tasks:
            <BR>1. <B>{1}</B> - Subscribe to the bot.<BR>2. <B>{2}</B> - Get bot status.<BR>3. <B>{3}</B> - Unsubscribe from the bot.
            <BR>4. <B>{4}</B> - Get help from the bot.</BODY></HTML>", kQuickParseUrl, "SUBSCRIBE", "STAUTS", "UNSUBSCRIBE", "HELP");

            IAccIm im = session.CreateIm(reply, "text/html");
            imSession.SendIm(im);
        }

        private void ReplyToSubList()
        {
            // respond to the list if an update has occured.
            string url = kEventUpdate;
            string reply = string.Format("<HTML><BODY><A HREF={0}>Southwest.com</A></BODY></HTML>",
                kQuickParseUrl);
            url = string.Format(url, reply, kLookupDate);

            int count = m_subList.Count;
            for (int i = 0; i < count; i++)
            {
                string subscriber = (string)m_subList[i];
                IAccImSession ims = s.CreateImSession(subscriber, AccImSessionType.AccImSessionType_Im);
                IAccIm im = s.CreateIm(url, "text/html");
                ims.SendIm(im);

                DateTime CurrTime = DateTime.Now;
                Console.WriteLine("> An update alert was sent to {0} @: {1:G}", subscriber, CurrTime);
            }
            return;
        }

        private void UpdateState()
        {	
		    // check the web page for an update
            try
            {
                string url = kQuickParseUrl;
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);				     					
                HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
                Stream stream = resp.GetResponseStream();
                StreamReader reader = new StreamReader(stream);
                string buf = reader.ReadToEnd();	
			
                DateTime CurrTime = DateTime.Now;
                if (buf.IndexOf(kLookupDate) > -1)
                {
                    Console.WriteLine("> WebPage checked with no change @: {0:G}", CurrTime);
                    return;
                }
                else
                {
                    Console.WriteLine("> WebPage checked with CHANGES! @: {0:G}", CurrTime);
                    ReplyToSubList();
                }

            }						
            catch (Exception e)
            {
                DumpException(e);				
            }
        }

        static private void DumpException(Exception e)
        {
            Console.WriteLine("{0}", e.ToString());							
        }
    }
}
	

Open AIM Widgets (AWIs)

View blSounds Code - This code will show you how to build your own AIM Widget via Javascript. A widget is a zip file with a renamed extension to AWI. AWIs work in AIM Lite and AIM 6.5. The package contains a plugin.xml file and a folder called content which contains a box file and a javascript file.

Plugin.XML - This file contains Open AIM information like developer key, name of the plugin and the version

<?xml version="1.0" encoding="utf-8" ?>    
<widget
    uuid = "{6A753147-414B-7766-594C-354738534E33}"
    version = "1.0"
    name = "My Cool Plugin"
    description = "This plugin does something nifty."
    vendor = "Coolness Inc."
/>
<widget>

main.box - This file contains the entry point for the plugin. It is psuedo UI using AOL's Boxely technology.

<?xml version="1.0" encoding="utf-8" ?>

<window
    xmlns="http://www.aol.com/boxely/box.xsd"
    xmlns:s="http://www.aol.com/boxely/style.xsd"
    xmlns:on="http://www.aol.com/boxely/reaction.xsd"
    on:constructed="onConstructed();"
    on:destroyed="onDestroyed();"
    s:height="0"
    s:width="0"
    hidden="true"
    collapsed="true"
    floating="true"
>
    <code id="main" language="jscript" src="main.js"/>
</window>
					
		

main.js - This file contains the business logic of the widget. The code below shows how you can listen for buddy arrive and depart events and how to play a sound when those events happen.

function onDestroyed()
{
    scene.disconnectObject("session_");
}


function onConstructed()
{
    var session = scene.paramsDictionary.valueForKey("session");
    scene.connectObject(session, "session_");
}

function session_OnUserChange(session, oldUser, newUser, property, result)
{
    var newState = newUser.State;
    var oldState = oldUser.State;
    if (newState >= 1)  // user signed online AccUserState_Online == 1
    	appUtils.playSound(scene, "online.wav");
    else if (oldState >= 1) //user signed offline
	appUtils.playSound(scene, "offline.wav");
}
		

Apple Script Sample

View AOL Radio Script - This code will show you how to listen and sniff AOL Radio on Mac OS X to capture the title, artist, and album of the current playing song.

on getInfoStr()
	tell application "AOL Radio"
		try
			set trk to current track
			set str to "Artist: " & (artist of trk)
			set str to str & ", Track: " & (name of trk)
			set str to str & ", Album: " & (album of trk)
			return str
		end try
	end tell
end getInfoStr

on subString(x, y, theString)
	return (characters x thru y of theString) as string
end subString

on getTime()
	tell application "AOL Radio"
		set tme to totaltime
		set ptme to playingtime
		return (tme / 1000) - (ptme / 1000) + 5
	end tell
end getTime

set done to false
set theDate to current date
set f to ((path to "docs" as text) & "AOLRadio_" & (time of theDate) & ".txt")
set nref to open for access file f with write permission
set eof nref to 0

on getDateInfo()
	set theDate to current date
	set str to "

"
	set str to str & date string of theDate
	set str to str & " " & time string of theDate & " "
	return str
end getDateInfo

repeat until done
	with timeout of 12 seconds
		write getDateInfo() & getInfoStr() starting at (1 + (get eof file f)) to file f
		delay getTime()
	end timeout
end repeat

Web AIM API sample

View Web AIM API sample - This code will show you a basic webpage that can send and receive an IM from a screen name. To view this page in action click here.

sampleWim.html - Simple html for the page.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Greg's Mind Web AIM API Sample</title>
<link rel="stylesheet" type="text/css" href="sampleWim.css" />
<script type="text/javascript" src="http://o.aolcdn.com/aim/web-aim/aimapi.js"></script>
<script type="text/javascript" src="sampleWim.js"></script>
</head>
<body>
	<div id="mContainer">
		<noscript>This sample requires a browser with javascript enabled. May I suggest <a href="http://getfirefox.com">Firefox?</a>.</noscript>
	</div>
</body>
</html>
		

sampleWim.css - Simple css for the page.

* {
	font:10px verdana;
}

#mContainer {
	width:523px;
	height:200px;
	position:relative;
	margin:auto;
	border:1px solid #dadada;
}

#dataDisplay {
	padding-top:5px;
	border-top:1px solid #dadada;
	width:516px;
	position:absolute;
	top:210px;
	left:5px;
	text-align:right;
}

.info {
	padding-top:5px;
	width:500px;
	position:relative;
	margin:auto;
}

#msgBox {
	position:absolute;
	border:2px solid #000;
	background-color:#FFF;
	padding:3px;
	width:200px;
	height:75px;
	top:40px;
	left:162px;
	text-align:center;
	z-index:1000;
	opacity:0.9;
}

#chatWindow {
	position:absolute;
	width:500px;
	height:80px;
	overflow:auto;
	background-color:#E9F1F5;
	border:1px solid #000;
	top:40px;
	left:5px;
	padding:2px;
}

#chatInput {
	position:absolute;
	width:500px;
	font:10px verdana;
	background-color:#DAE2E6;
	border:1px solid #000;
	top:140px;
	left:5px;
	padding:2px;
}

#chatTo {
	position:absolute;
	width:500px;
	font:10px verdana;
	background-color:#DAE2E6;
	border:1px solid #000;
	top:19px;
	left:5px;
	padding:2px;
}

/* Auth Window Appearence */
.AIMFrameContainer {
	position:absolute;
	width:530px;
	height:380px;
	top:5px;
	border:2px solid #000;
	z-index:1000;
	background-color:#FFF;
}

.AIMFrameContainer iframe {
	width:530px;
	height:350px;
	border-style:none;
}

.AIMFrameContainer h2 {
	padding:4px;
	margin:0;
	height:18px;
	font:bold 10px verdana,arial,helvetica;
	background-color:#EAEAEA;
	color:#000;
	border-bottom:1px solid #000;
}		

sampleWim.js - Javascript for the page that contains the business logic for the connection to AIM.

/*****
*  Web AIM API Sample
*  This sample shows how to log into AIM
*  and have a chat window embeded on a web
*  page for sending and receiving IMs
*****/
function dummy(){};

var d = document;
var sample = {
	remoteUser:null,
	init : function()
	{
		sample.ui.createUI();
		AIM.params.callbacks.listener.im = ["sample.com.acceptIncomingText"];
		AIM.params.callbacks.sendTextIM = ["sample.com.acceptTextIM"];
		AIM.params.callbacks.listener.buddylist = ["dummy"];
		
		AIM.params.wimKey = "gr1meF10bwWdnP16";
		AIM.core.subscriptions = "buddylist,im";
		AIM.transactions.getToken(AIM.core.subscriptions);		
	},
	com : {
		acceptTextIM: function(json) {
			switch(json.response.statusCode) {
				case 200:
				  break;
				case 602:
					alert("That user is not currently online.");
					break;				
				case 401:
				case 450:
					AIM.core.createAuthWindow(json.response.data.redirectURL + "?k=" + AIM.params.wimKey);
					AIM.core.pendingTransaction = {
						msg:AIM.core.AIMData[json.response.requestId].objData.data,
						to:AIM.core.AIMData[json.response.requestId].objData.to,
						type:"sendTextIM"
					}
					break;
				default:
					alert("Something unexpected occured. Error code is " + json.response.statusCode);
					break;
			}
		},		
		acceptIncomingText: function(json) {
			var to = d.getElementById("chatTo");
			if (to.value.length == 0) {
				to.value = json.source.displayId;
			}
			var cContainer = d.getElementById("chatWindow");
			var str = "<b style=\"color:blue;\">" + json.source.displayId + "</b>: " + json.message + "<br />";
			cContainer.innerHTML += str;
			cContainer.scrollTop = cContainer.scrollHeight;
		}
	},
	
	ui : {		
		prepWork: function() {
			d.getElementById("chatTo").style.display = "block";
			d.getElementById("chatWindow").style.display = "block";
			d.getElementById("chatInput").style.display = "block";
			d.getElementById("msgBox").style.display = "none";
		},
		
		createUI:function() {	
			var str = "<b> Send Message To:</b><br>"
			d.getElementById("mContainer").innerHTML += str;
			var oChatTo = d.createElement("input");
			oChatTo.setAttribute("id","chatTo");
			oChatTo.setAttribute("type","text");
			d.getElementById("mContainer").appendChild(oChatTo);
					
			var oChatWindow = d.createElement("div");
			oChatWindow.setAttribute("id","chatWindow");
			d.getElementById("mContainer").appendChild(oChatWindow);
			
			var oChatInput = d.createElement("input");
			oChatInput.setAttribute("id","chatInput");
			oChatInput.setAttribute("type","text");
			oChatInput.onkeyup = function(e) {
				var keyCode = window.event?event.keyCode:e.keyCode;
				if(keyCode == 13) {
					var cContainer = d.getElementById("chatWindow");
					var to = d.getElementById("chatTo");
					cContainer.innerHTML += "<b style=\"color:red;\">" + AIM.params.user + "</b>: " + this.value + "<br />";
					cContainer.scrollTop = cContainer.scrollHeight;
					AIM.transactions.sendTextIM(to.value, this.value);
					this.value = "";	
				}
			}
			d.getElementById("mContainer").appendChild(oChatInput);
		}		
	}				
}

window.onload = sample.init;
window.onunload = function() {
		AIM.transactions.sendTextIM(sample.remoteUser,"bye");
		AIM.transactions.endSession();
}
	

C++ AIM Plugin Shell

View C++ AIM Plugin Shell - This code will show you the base AIM Plugin project. Once you have the code opened in Visual Studio, all you have to do is add your own logic. You can download the entire project here.

stdafx.h - Standard header file that has a few addition includes for Open AIM headers.

// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently,
// but are changed infrequently

#pragma once

#ifndef STRICT
#define STRICT
#endif

// Modify the following defines if you have to target a platform prior to the ones specified below.
// Refer to MSDN for the latest info on corresponding values for different platforms.
#ifndef WINVER				// Allow use of features specific to Windows 95 and Windows NT 4 or later.
#define WINVER 0x0400		// Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
#endif

#ifndef _WIN32_WINNT		// Allow use of features specific to Windows NT 4 or later.
#define _WIN32_WINNT 0x0400	// Change this to the appropriate value to target Windows 2000 or later.
#endif						

#ifndef _WIN32_WINDOWS		// Allow use of features specific to Windows 98 or later.
#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
#endif

#ifndef _WIN32_IE			// Allow use of features specific to IE 4.0 or later.
#define _WIN32_IE 0x0400	// Change this to the appropriate value to target IE 5.0 or later.
#endif

#define _ATL_APARTMENT_THREADED
#define _ATL_NO_AUTOMATIC_NAMESPACE

// turns off ATL's hiding of some common and often safely ignored warning messages
#define _ATL_ALL_WARNINGS

#ifndef _countof
#define _countof(array) (sizeof(array)/sizeof(array[0]))
#endif

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace ATL;
// the open AIM dll for linking to the Open AIM Interfaces
// this is the default install location for AIM6.  If AIM
// is not installed here then locate the path for acccore.dll
// and replace what is declared below.
#import "C:\Program Files\AIM6\acccore.dll" raw_interfaces_only, raw_native_types, no_namespace, named_guids, auto_search

// add include helpers for AccDispid for events and
// AccSupport for object and string helpers
// You will need to set the project settings for these
// files to find them.  Right click on the project name
// and choose properties.  Select the configuration drop down
// and choose All configurations.
// Now choose C\C++ in the list on the left and in the general
// section for the Additional include directories add the path
// for the two files below.  The files can be found in our SDK
// in the include directory for AccSupport.h and include\interfaces
// directory for AccDispid.h
#include "AccDispid.h"
#include "AccSupport.h"

#pragma warning(disable: 4199)

AIMPluginBaseClass.h - This is the header file for the plugin. It declares the class that is the plugin and inherits IAccPlugin and IAccCommandTarget, in addition the file shows how to hook AIM events.

// AIMPluginBaseClass.h : Declaration of the CAIMPluginBaseClass

#pragma once
#include "resource.h"       // main symbols


// IAIMPluginBaseClass
[
	object,
	uuid("CE1BBD81-827A-462C-A61A-16DE90449DB9"),
	dual,	helpstring("IAIMPluginBaseClass Interface"),
	pointer_default(unique)
]
__interface IAIMPluginBaseClass : IDispatch
{
};



// CAIMPluginBaseClass

// Go to developer.aim.com to get a plugin developer key
// copy the UUID and paste it below.
[
    coclass,
    threading("apartment"),
    vi_progid("AIMBasePluginProject.AIMPluginBaseClass"),
    progid("AIMBasePluginProject.AIMPluginBaseCla.1"),
    version(1.0),
    //uuid("YOUR KEY GOES HERE"),
    helpstring("AIMPluginBaseClass Class")
]
class ATL_NO_VTABLE CAIMPluginBaseClass : 
    public IAIMPluginBaseClass,  
    public IAccCommandTarget,     // this interface is to add a menu item inside the AIM client
    public IAccPlugin,            // this interface is to inform the plugin of Init and Shutdown of the plugin
    // DAccEvents interface hooks all the Open AIM events
    public IDispEventImpl<1, CAIMPluginBaseClass, &__uuidof(DAccEvents), &LIBID_AccCoreLib, /* wMajor = */ 1, /* wMinor = */ 0>
{
public:
    CAIMPluginBaseClass()
    {
    }


    DECLARE_PROTECT_FINAL_CONSTRUCT()

    // Plugin Registry information goes in the Macro below
    // replace the values below with strings that will appear in the
    // registry and in the Plugins preferences of the AIM client.
    ACC_DECLARE_REGISTRY("Name of plugin", "Version Number", "Description", "Plugin Download URL", "Company", "Company URL")

    // DAccEvents map
    // the map below is the way to register for open AIM events.
    // for example below is the event to be notified of a session
    // signing online to the AIM Cloud and signing off of the cloud
    // to be notified of an incoming IM you would add a new SINK_ENTRY, i.e.
    // SINK_ENTRY_EX(1, __uuidof(DAccEvents), ACCDISPID_ONIMRECEIVED, OnImReceived)
    // the ACCDISPID_* is defined in AccDispid.h the "OnStateChange" is a function to 
    // receive the event and is defined below
    BEGIN_SINK_MAP(CAIMPluginBaseClass)         
        SINK_ENTRY_EX(1, __uuidof(DAccEvents), ACCDISPID_ONSTATECHANGE, OnStateChange)
    END_SINK_MAP() 

    HRESULT FinalConstruct()
    {
        return S_OK;
    }

    void FinalRelease() 
    {
    }
 

public:
    // IAccCommandTarget Methods
    STDMETHOD(QueryStatus)(int command, VARIANT users, VARIANT_BOOL * enabled);
    STDMETHOD(Exec)(int command, VARIANT users);

    // IAccPlugin Methods
    STDMETHOD(Init)(IAccSession * session, IAccPluginInfo * pluginInfo);
    STDMETHOD(Shutdown)();
    STDMETHOD(OnStateChange)(IAccSession* session, AccSessionState state, HRESULT hr);

private:
    const static int kCommandId = 1;
    CComPtr m_spiSession;  
};
		

AIMPluginBaseClass.cpp - This file is the c++ class file. The code below implements the IAccPlugin and IAccCommandTarget functions in addition to the OnStateChange event declared in the header above.

// AIMPluginBaseClass.cpp : Implementation of CAIMPluginBaseClass

#include "stdafx.h"
#include "AIMPluginBaseClass.h"


// CAIMPluginBaseClass
// Init/term methods. Load the plugin's preferences.
STDMETHODIMP CAIMPluginBaseClass::Init(IAccSession * piAccSession, IAccPluginInfo* piPluginInfo)
{
    // declare a member variable IAccSession in our AIMPluginBaseClass.h
    // hold a reference of the session in the new
    // member variable for later
    m_spiSession = session;

    // declare kCommandId in our AIMPluginBaseClass.h  
    // and create a new IAccCommand
    // add the menu text
    CComPtr  spiCommand;
    pluginInfo->AddCommand(kCommandId, &spiCommand);
    spiCommand->put_Property(AccCommandProp_Text, CComVariant(L"Menu TEXT HERE"));

    // notify ATL that you want to receive Open AIM events
    return DispEventAdvise(m_spiSession);
}

STDMETHODIMP CAIMPluginBaseClass::Shutdown()
{
    // unadvise ATL that you no longer need events from Open AIM
    DispEventUnadvise(m_spiSession);

    // release the reference you have to the IAccSession
    m_spiSession = NULL;
    return S_OK;;
}

// Command handlers
STDMETHODIMP CAIMPluginBaseClass::QueryStatus(int command, VARIANT, VARIANT_BOOL* enabled)
{
    // Say we support a command
    if (command == kCommandId)
    {
        *enabled = VARIANT_TRUE;
        return S_OK;
    }
    else
    {
        return E_FAIL;
    }      
}

STDMETHODIMP CAIMPluginBaseClass::Exec(int command, VARIANT)
{
    // if our command is called then we should do something
    // replace the return S_OK with your own logic.
    if (command == kCommandId)
        return S_OK;
    else
        return E_INVALIDARG;        
}

STDMETHODIMP CAIMPluginBaseClass::OnStateChange(IAccSession* session, AccSessionState state, HRESULT hr)
{
    // do something here, maybe pop a window when you are receive
    // an AccSessionState == AccSessionState_Online
    return E_NOTIMPL;
}
		

All code is copywrite AOL, LLC and property of Gregory Cypes, though can be used for reference for building Open AIM Applications