From 8d6d06dbfe4b2d1746a619abaa5a7f4001e69459 Mon Sep 17 00:00:00 2001 From: plfiorini Date: Wed, 12 May 2010 20:42:46 +0000 Subject: [PATCH] Adding AIM protocol from Alexander Botero-Lowry, but it needs polishing. --- application/ContactLinker.cpp | 2 +- application/Server.cpp | 2 +- libs/Jamfile | 5 +- libs/libimcomm/COPYING | 29 + libs/libimcomm/Jamfile | 12 + libs/libimcomm/README | 190 +++++ libs/libimcomm/bos_signon.c | 684 ++++++++++++++++ libs/libimcomm/byteswap.h | 7 + libs/libimcomm/flap.c | 490 +++++++++++ libs/libimcomm/imcomm.c | 770 ++++++++++++++++++ libs/libimcomm/imcomm.h | 311 +++++++ libs/libimcomm/makeprotos-sed | 18 + libs/libimcomm/md5.c | 394 +++++++++ libs/libimcomm/md5.h | 98 +++ libs/libimcomm/misc.c | 25 + libs/libimcomm/mkprotos | 6 + libs/libimcomm/packet.c | 303 +++++++ libs/libimcomm/protos.h | 109 +++ libs/libimcomm/proxy.c | 227 ++++++ libs/libimcomm/snac.c | 1433 +++++++++++++++++++++++++++++++++ libs/libimcomm/test.c | 186 +++++ libs/libjabber/Jamfile | 2 - protocols/Jamfile | 1 + protocols/aim/AIM.cpp | 496 ++++++++++++ protocols/aim/AIM.h | 58 ++ protocols/aim/Jamfile | 23 + protocols/aim/aim.rdef | 34 + protocols/aim/main.cpp | 8 + 28 files changed, 5917 insertions(+), 6 deletions(-) create mode 100644 libs/libimcomm/COPYING create mode 100644 libs/libimcomm/Jamfile create mode 100644 libs/libimcomm/README create mode 100644 libs/libimcomm/bos_signon.c create mode 100644 libs/libimcomm/byteswap.h create mode 100644 libs/libimcomm/flap.c create mode 100644 libs/libimcomm/imcomm.c create mode 100644 libs/libimcomm/imcomm.h create mode 100644 libs/libimcomm/makeprotos-sed create mode 100644 libs/libimcomm/md5.c create mode 100644 libs/libimcomm/md5.h create mode 100644 libs/libimcomm/misc.c create mode 100644 libs/libimcomm/mkprotos create mode 100644 libs/libimcomm/packet.c create mode 100644 libs/libimcomm/protos.h create mode 100644 libs/libimcomm/proxy.c create mode 100644 libs/libimcomm/snac.c create mode 100644 libs/libimcomm/test.c create mode 100644 protocols/aim/AIM.cpp create mode 100644 protocols/aim/AIM.h create mode 100644 protocols/aim/Jamfile create mode 100644 protocols/aim/aim.rdef create mode 100644 protocols/aim/main.cpp diff --git a/application/ContactLinker.cpp b/application/ContactLinker.cpp index 3746549..56e5359 100644 --- a/application/ContactLinker.cpp +++ b/application/ContactLinker.cpp @@ -30,7 +30,7 @@ ContactLinker::ContactLinker(BString id, BMessenger msgn) RegisterObserver(fRosterItem); // By default we use protocol icon as avatar icon - fAvatarBitmap = ProtocolManager::Get()->GetProtocolIcon("gtalk"); + fAvatarBitmap = ProtocolManager::Get()->GetProtocolIcon("aim"); } diff --git a/application/Server.cpp b/application/Server.cpp index 9175d9a..50e447e 100644 --- a/application/Server.cpp +++ b/application/Server.cpp @@ -26,7 +26,7 @@ Server::Server(MainWindow* mainWindow) : BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE) { - CayaProtocol* pp = ProtocolManager::Get()->GetProtocol("gtalk"); + CayaProtocol* pp = ProtocolManager::Get()->GetProtocol("aim"); if (!pp) debugger("something wrong"); diff --git a/libs/Jamfile b/libs/Jamfile index f5d58b5..0fa38b6 100644 --- a/libs/Jamfile +++ b/libs/Jamfile @@ -1,7 +1,8 @@ SubDir TOP libs ; # Include all the components. -SubInclude TOP libs libjabber ; SubInclude TOP libs librunview ; -SubInclude TOP libs libinterface ; +SubInclude TOP libs libjabber ; SubInclude TOP libs libsupport ; +SubInclude TOP libs libinterface ; +SubInclude TOP libs libimcomm ; diff --git a/libs/libimcomm/COPYING b/libs/libimcomm/COPYING new file mode 100644 index 0000000..63836a7 --- /dev/null +++ b/libs/libimcomm/COPYING @@ -0,0 +1,29 @@ +Copyright (C) 2003-2005, Claudio Leite +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the BSF Software Project nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/libs/libimcomm/Jamfile b/libs/libimcomm/Jamfile new file mode 100644 index 0000000..6437228 --- /dev/null +++ b/libs/libimcomm/Jamfile @@ -0,0 +1,12 @@ +SubDir TOP libs libimcomm ; + +StaticLibrary libimcomm.a : + misc.c + packet.c + flap.c + bos_signon.c + imcomm.c + snac.c + md5.c + proxy.c +; diff --git a/libs/libimcomm/README b/libs/libimcomm/README new file mode 100644 index 0000000..b1b8459 --- /dev/null +++ b/libs/libimcomm/README @@ -0,0 +1,190 @@ + +This is rather roughly written at the moment. Please forgive any grammar +mistakes I made when I rushed this together. + +-Claudio + +----- +IMCOMM REFERENCE GUIDE + +1. Data structures + + IMComm operates on "handles," which are simply structures filled + with the information IMComm needs for one single IM session. In + order to allow multiple connections per program, IMComm leaves + the pointers to those structures up to the user. + + Users should use a void * pointer to set up the structure. + + Example: + + void *handle; + + handle = imcomm_create_handle(); + +2. Callbacks + + All IMComm events operate on callbacks. The list of events can + be found in imcomm.h. Developers should register the callbacks + after creating a handle and before signing on. + + Example: + + imcomm_register_callback(handle, IMCOMM_IM_INCOMING, incoming_im); + + This will make the library call the function incoming_im when + an incoming message is received on the conncection pointed by + handle. + + The first parameter a for any called back function is the handle. + Following that, the parameter varies based on the event type. + +3. Signing on + + Signing on is rather simple. + + imcomm_im_signon(handle, username, password); + +4. Errors and status + + All errors are handled using callbacks. To register the error callback, + use the IMCOMM_ERROR callback ID with imcomm_register_callback(); + + The error types are in an enumerated list in imcomm.h + + for example: + + void error_cb(void *handle, int event) + { + switch(event) { + case IMCOMM_STATUS_CONNECTED: + printf("Connected.\n"); + break; + } + } + +EVENTS CURRENTLY IMPLEMENTED: + +IMCOMM_IM_SIGNON +(void *handle, char *who) + +Buddy has come online. + +IMCOMM_IM_SIGNOFF +(void *handle, char *who) + +Buddy has gone offline. + +IMCOMM_IM_BUDDYAWAY +(void *handle, char *who) + +Buddy is away. + +IMCOMM_IM_BUDDYUNAWAY +(void *handle, char *who) + +Buddy is no longer away. + +IMCOMM_IM_IDLEINFO +(void *handle, char *who, long idletime) + +Buddy's idletime, reported in minutes. + +IMCOMM_IM_INCOMING +(void *handle, char *who, int automessage, char *message) + + has sent you a message. If automessage is 1, then +the message is an auto response. + +IMCOMM_IM_PROFILE +(void *handle, char *who, char *profile) + +Buddy's profile after a profile request. + +IMCOMM_IM_AWAYMSG +(void *handle, char *who, char *msg) + +Buddy's away message after a away message request. + +IMCOMM_ERROR +(void *handle, int errortype, void *ptr1, void *ptr2, void *ptr3) + +Error of error . ptr1-3 are currently unused. + + +FUNCTIONS FOR PROGRAMMERS + +imcomm_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) + +This is where the main work is done. It behaves just like a standard +select() call, meaning it can be used to multiplex keyboard input and +AIM input. + +It cycles through every handle known to IMComm (a list is kept internally), +checking for input and processing if necessary. + +Example: + +fd_set readfs; +struct timeval tm; + +while(1) { + FD_ZERO(&readfs); + FD_SET(fileno(stdin), &readfs); + tm.tv_sec = 1; + tm.tv_usec = 15; + + /* + * this will check fileno(stdin) AND all of the + * sessions currently established. + */ + imcomm_select(fileno(stdin), &readfs, NULL, NULL &tm); + + if(FD_ISSET(fileno(stdin))) { + /* keyboard input handler */ + } +} + + +imcomm_set_profile(void *handle, char *profile); + +Sets the user profile. + +imcomm_set_away(void *handle, char *msg); + +Sets away message. + +imcomm_set_unaway(void *handle); + +Unsets away message. + +imcomm_im_send_message(void *handle, const char *whom, const char *msg, int automsg); + +Sends message to user . If automsg is 1, then it is sent as +an auto response. + +imcomm_request_profile(void *handle, char *sn); + +Requests profile for user . + +imcomm_request_awaymsg(void *handle, char *sn); + +Requests away message for user . + +imcomm_im_add_buddy(void *handle, char *sn); + +Adds buddy to session buddy list. + +imcomm_im_remove_buddy(void *handle, char *sn); + +Removes buddy from session buddy list. + +imcomm_compare_nicks(void *handle, char *sn1, char *sn2) + +Compares two screen names, ignoring spaces and case. + +char *imcomm_simplify_sn(char *sn) + +Returns a simplified version of a screen name, all lowercase +with no spaces. Note that you must free this string later, +since it is malloc'ed by imcomm. diff --git a/libs/libimcomm/bos_signon.c b/libs/libimcomm/bos_signon.c new file mode 100644 index 0000000..ad6065a --- /dev/null +++ b/libs/libimcomm/bos_signon.c @@ -0,0 +1,684 @@ +/** _ + ** (_)_ __ __ ___ _ __ _ __ + ** | | ' \/ _/ _ \ ' \| ' \ + ** |_|_|_|_\__\___/_|_|_|_|_|_| + ** + ** Copyright (C) 2003-2005, Claudio Leite + ** All rights reserved. + ** + ** Please see the file 'COPYING' for licensing information. + **/ + +#include "imcomm.h" + +#ifdef MD5_LOGIN +#include "md5.h" +#endif + +#define CLIENT_IDENT "AOL Instant Messenger, version 5.5.3595/WIN32" + +#ifdef MACINTOSH_CLASSIC + +/* + * Thanks to PuTTY source code for a lot of help on the MacTCP stuff. + * Learning obsolete API's can be rather difficult... + * + * This should explain the similarities on variable and function names. + */ + +int initialized = 0; +short refnum; +ProcessSerialNumber psn; +static pascal void mactcp_lookupdone(struct hostInfo *, char *); +static pascal void +mactcp_asr(StreamPtr, unsigned short, Ptr, + unsigned short, struct ICMPReport *); +static ResultUPP mactcp_lookupdone_upp; +static TCPNotifyUPP mactcp_asr_upp; +OSErr err; + +static pascal void +mactcp_lookupdone(struct hostInfo * hi, char *cookie) +{ + volatile int *donep = (int *) cookie; + + *donep = TRUE; +} + +static pascal void +mactcp_asr(StreamPtr str, unsigned short event, Ptr cookie, + unsigned short termin_reason, struct ICMPReport * icmp) +{ + WakeUpProcess(&psn); +} + +void +mactcp_close(void *handle) +{ + TCPiopb pb; + + pb.ioCRefNum = refnum; + pb.csCode = TCPClose; + pb.tcpStream = ((IMCOMM *) handle)->s; + pb.csParam.close.validityFlags = 0; + pb.csParam.close.userDataPtr = (Ptr) handle; + PBControlSync((ParmBlkPtr) & pb); + + pb.ioCRefNum = refnum; + pb.csCode = TCPAbort; + pb.tcpStream = ((IMCOMM *) handle)->s; + pb.csParam.abort.userDataPtr = (Ptr) handle; + PBControlSync((ParmBlkPtr) & pb); + + pb.ioCRefNum = refnum; + pb.csCode = TCPRelease; + pb.tcpStream = ((IMCOMM *) handle)->s; + pb.csParam.create.userDataPtr = (Ptr) handle; + err = PBControlSync((ParmBlkPtr) & pb); + if (err == noErr) + free(pb.csParam.create.rcvBuff); +} +#endif + +/* PROTO */ +IMCOMM_RET +imcomm_im_signon(void *handle, const char *sn, const char *pw) +{ + IMCOMM_RET ret; + pkt_t *packet; + +#ifdef MACINTOSH_CLASSIC + OSErr err; + struct hostInfo hostinfo; + volatile int resolverDone = FALSE; + TCPiopb pb; + UDPiopb upb; + size_t buflen; +#else + struct sockaddr_in sin; + struct hostent *he; +#endif + +#ifndef MD5_LOGIN + const char client_ident[] = CLIENT_IDENT; + const unsigned char roaststring[] = + {0xF3, 0x26, 0x81, 0xC4, 0x39, 0x86, 0xDB, 0x92, 0x71, 0xA3, 0xB9, + 0xE6, 0x53, 0x7A, 0x95, 0x7C}; + unsigned char *roastpw; + int x; +#else + pkt_t *pk2; +#endif + +#ifdef MACINTOSH_CLASSIC + if (!initialized) { + err = OpenDriver("\p.IPP", &refnum); + if (err != noErr) { + printf("Error initializing driver.\n"); + return IMCOMM_RET_ERROR; + } + err = OpenResolver(NULL); + if (err != noErr) { + printf("Error initializing resolver.\n"); + return IMCOMM_RET_ERROR; + } + mactcp_lookupdone_upp = NewResultProc(&mactcp_lookupdone); + mactcp_asr_upp = NewTCPNotifyProc(&mactcp_asr); + initialized = 1; + } + err = + StrToAddr("login.oscar.aol.com", &hostinfo, mactcp_lookupdone_upp, + (char *) &resolverDone); + if (err == cacheFault) + while (!resolverDone) + continue; + + upb.ioCRefNum = refnum; + upb.csCode = UDPMaxMTUSize; + upb.csParam.mtu.remoteHost = hostinfo.addr[0]; + upb.csParam.mtu.userDataPtr = (Ptr) handle; + err = PBControlSync((ParmBlkPtr) & upb); + if (err != noErr) { + printf("Error retrieving MTU.\n"); + return IMCOMM_RET_ERROR; + } + buflen = upb.csParam.mtu.mtuSize * 4 + 1024; + if (buflen < 4096) + buflen = 4096; + + GetCurrentProcess(&psn); + + pb.ioCRefNum = refnum; + pb.csCode = TCPCreate; + pb.csParam.create.rcvBuff = malloc(buflen); + pb.csParam.create.rcvBuffLen = buflen; + pb.csParam.create.notifyProc = mactcp_asr_upp; + pb.csParam.create.userDataPtr = (Ptr) handle; + err = PBControlSync((ParmBlkPtr) & pb); + if (err != noErr) { + printf("Error creating TCP stream.\n"); + return IMCOMM_RET_ERROR; + } + ((IMCOMM *) handle)->s = pb.tcpStream; + + pb.ioCRefNum = refnum; + pb.csCode = TCPActiveOpen; + pb.tcpStream = ((IMCOMM *) handle)->s; + pb.csParam.open.validityFlags = 0; + pb.csParam.open.remoteHost = hostinfo.addr[0]; + pb.csParam.open.remotePort = ((IMCOMM *) handle)->oscarport; + pb.csParam.open.localPort = 0; + pb.csParam.open.timeToLive = 0; + pb.csParam.open.security = 0; + pb.csParam.open.optionCnt = 0; + pb.csParam.open.userDataPtr = (Ptr) handle; + err = PBControlSync((ParmBlkPtr) & pb); + if (err != noErr) { + printf("Connection failed.\n"); + return IMCOMM_RET_ERROR; + } + ((IMCOMM *) handle)->readable = 1; +#else + /* XXX insert modular socket code here */ +#ifdef __MINGW32__ + if (WSAStartup(0x101, &((IMCOMM *) handle)->wsadata)) { + printf("ERROR: %i\n", WSAGetLastError()); + return IMCOMM_RET_ERROR; + } +#endif + + if (((IMCOMM *) handle)->proxymode == PROXY_TYPE_SOCKS5) { + connect_socks5(handle, "login.oscar.aol.com", + ((IMCOMM *) handle)->oscarport); + } else if (((IMCOMM *) handle)->proxymode == PROXY_TYPE_HTTPS) { + connect_https(handle, "login.oscar.aol.com", + ((IMCOMM *) handle)->oscarport); + } else { + if ((he = gethostbyname("login.oscar.aol.com")) == NULL) { + perror("gethostbyname()"); + return IMCOMM_RET_ERROR; + } + if ((((IMCOMM *) handle)->socket = + socket(AF_INET, SOCK_STREAM, 0)) == -1) { + perror("socket()"); + return IMCOMM_RET_ERROR; + } + sin.sin_family = AF_INET; + sin.sin_port = htons(((IMCOMM *) handle)->oscarport); + + sin.sin_addr = *((struct in_addr *) he->h_addr); + memset(&(sin.sin_zero), 0, 8); + + if (connect + (((IMCOMM *) handle)->socket, (struct sockaddr *) & sin, + sizeof(struct sockaddr)) == -1) { + perror("connect()"); + return IMCOMM_RET_ERROR; + } + } + /* end socket code for now */ +#endif + +#ifdef MD5_LOGIN + ((IMCOMM *) handle)->pw = strdup((char *) pw); + ((IMCOMM *) handle)->sn = strdup((char *) sn); + packet = pkt_init(12 + strlen(sn)); +#else + roastpw = malloc(strlen(pw) + 1); + memset(roastpw, 0, strlen(pw) + 1); + + for (x = 0; x < (int) strlen(pw); x++) + roastpw[x] = (pw[x] ^ roaststring[x]); + + packet = pkt_init(66 + strlen(client_ident) + strlen(sn) + strlen(pw)); + + pkt_add32(packet, 0x00000001); +#endif + + /* + * I should really build a TLV here instead, but this works. + */ + + /* + * Add SN length + SN + */ + pkt_add16(packet, 0x0001); + pkt_add16(packet, (uint16_t) strlen(sn)); + pkt_addraw(packet, (uint8_t *) sn, strlen(sn)); + +#ifdef MD5_LOGIN + /* + * Add unknown TLV's... + */ + pkt_add16(packet, 0x004B); + pkt_add16(packet, 0x0000); + pkt_add16(packet, 0x005A); + pkt_add16(packet, 0x0000); +#else + /* + * Add roasted PW length + roasted PW + */ + pkt_add16(packet, 0x0002); + pkt_add16(packet, (uint16_t) strlen(pw)); + pkt_addraw(packet, (uint8_t *) pw, strlen(pw)); + + /* + * Add client ident string + */ + pkt_add16(packet, 0x0003); + pkt_add16(packet, (uint16_t) strlen(client_ident)); + pkt_addraw(packet, (uint8_t *) client_ident, strlen(client_ident)); + + /* + * Add client ID (hardcoded) + */ + pkt_add16(packet, 0x0016); + pkt_add16(packet, 0x0002); + pkt_add16(packet, 0x0109); + + /* + * Add client versions (hardcoded) + */ + pkt_add16(packet, 0x0017); + pkt_add16(packet, 0x0002); + pkt_add16(packet, 0x0005); + pkt_add16(packet, 0x0018); + pkt_add16(packet, 0x0002); + pkt_add16(packet, 0x0005); + pkt_add16(packet, 0x0019); + pkt_add16(packet, 0x0002); + pkt_add16(packet, 0x0000); + pkt_add16(packet, 0x001A); + pkt_add16(packet, 0x0002); + pkt_add16(packet, 0x0057); + pkt_add16(packet, 0x0014); + pkt_add16(packet, 0x0004); + pkt_add32(packet, 0x000000ef); + pkt_add16(packet, 0x000F); + pkt_add16(packet, 0x0002); + pkt_addraw(packet, (unsigned char *) "en", 2); + pkt_add16(packet, 0x000E); + pkt_add16(packet, 0x0002); + pkt_addraw(packet, (unsigned char *) "us", 2); +#endif + +#ifdef MD5_LOGIN + pk2 = pkt_init(4); + pkt_add32(pk2, 0x00000001); + flap_sendpkt(handle, 0x01, pk2, 0); + pkt_free(pk2); + + ret = snac_sendpkt(handle, 0x17, 0x06, packet, 0); +#else + ret = flap_sendpkt(handle, 0x01, packet, 0); + free(roastpw); +#endif + pkt_free(packet); + return ret; + +} + +/* PROTO */ +IMCOMM_RET +bos_signon_phase2(void *handle, unsigned const char *server, unsigned const char *cookie, uint16_t cookie_len) +{ + char *host; + uint16_t port; + pkt_t *packet; + int x, ret; + int newlen; + +#ifdef MACINTOSH_CLASSIC + OSErr err; + struct hostInfo hostinfo; + volatile int resolverDone = FALSE; + TCPiopb pb; + UDPiopb upb; + size_t buflen; +#else + struct sockaddr_in sin; +#endif + +#if defined(PLAN9) || defined(__MINGW32__) + long addy; + struct in_addr ina; +#else + struct hostent *he; +#endif + + port = atoi(strchr((char *) server, ':') + 1); + + host = (char *) malloc(strlen((char *) server) + 1); + +#ifdef __OpenBSD__ + strlcpy(host, (char *) server, strlen((char *) server)); +#else + strcpy(host, (char *) server); +#endif + + for (x = 0; x < (int) strlen(host); x++) + if (host[x] == ':') { + host[x] = 0; + break; + } +#ifdef MACINTOSH_CLASSIC + mactcp_close(handle); + ((IMCOMM *) handle)->readable = 0; + + err = + StrToAddr(host, &hostinfo, mactcp_lookupdone_upp, + (char *) &resolverDone); + if (err == cacheFault) + while (!resolverDone) + continue; + + upb.ioCRefNum = refnum; + upb.csCode = UDPMaxMTUSize; + upb.csParam.mtu.remoteHost = hostinfo.addr[0]; + upb.csParam.mtu.userDataPtr = (Ptr) handle; + err = PBControlSync((ParmBlkPtr) & upb); + if (err != noErr) { + printf("Error retrieving MTU.\n"); + return IMCOMM_RET_ERROR; + } + buflen = upb.csParam.mtu.mtuSize * 4 + 1024; + if (buflen < 4096) + buflen = 4096; + + pb.ioCRefNum = refnum; + pb.csCode = TCPCreate; + pb.csParam.create.rcvBuff = malloc(buflen); + pb.csParam.create.rcvBuffLen = buflen; + pb.csParam.create.notifyProc = mactcp_asr_upp; + pb.csParam.create.userDataPtr = (Ptr) handle; + err = PBControlSync((ParmBlkPtr) & pb); + if (err != noErr) { + printf("Error creating TCP stream.\n"); + return IMCOMM_RET_ERROR; + } + ((IMCOMM *) handle)->s = pb.tcpStream; + + pb.ioCRefNum = refnum; + pb.csCode = TCPActiveOpen; + pb.tcpStream = ((IMCOMM *) handle)->s; + pb.csParam.open.validityFlags = 0; + pb.csParam.open.remoteHost = hostinfo.addr[0]; + pb.csParam.open.remotePort = port; + pb.csParam.open.localPort = 0; + pb.csParam.open.timeToLive = 0; + pb.csParam.open.security = 0; + pb.csParam.open.optionCnt = 0; + pb.csParam.open.userDataPtr = (Ptr) handle; + err = PBControlSync((ParmBlkPtr) & pb); + if (err != noErr) { + printf("Connection failed.\n"); + return IMCOMM_RET_ERROR; + } + ((IMCOMM *) handle)->readable = 1; + +#else + if (((IMCOMM *) handle)->ischild == 0) + shutdown(((IMCOMM *) handle)->socket, 0x02); + + if (((IMCOMM *) handle)->proxymode == PROXY_TYPE_SOCKS5) { + connect_socks5(handle, host, port); + } else if (((IMCOMM *) handle)->proxymode == PROXY_TYPE_HTTPS) { + connect_https(handle, host, port); + } else { + +#if !defined(PLAN9) && !defined(__MINGW32__) + if ((he = gethostbyname(host)) == NULL) { + perror("gethostbyname()"); + free(host); + return IMCOMM_RET_ERROR; + } + free(host); +#else + addy = inet_addr(host); + ina.s_addr = addy; + free(host); +#endif + + if ((((IMCOMM *) handle)->socket = + socket(AF_INET, SOCK_STREAM, 0)) == -1) { + perror("socket()"); + return IMCOMM_RET_ERROR; + } + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + +#if defined(PLAN9) || defined(__MINGW32__) + sin.sin_addr = ina; +#else + sin.sin_addr = *((struct in_addr *) he->h_addr); +#endif + + memset(&(sin.sin_zero), 0, 8); + + if (connect + (((IMCOMM *) handle)->socket, (struct sockaddr *) & sin, + sizeof(struct sockaddr)) == -1) { + perror("connect()"); + return IMCOMM_RET_ERROR; + } +#endif + } + + newlen = cookie_len + 8; + packet = pkt_init(newlen); + pkt_add32(packet, 0x00000001); + pkt_add16(packet, 0x0006); + pkt_add16(packet, cookie_len); + pkt_addraw(packet, (uint8_t *) cookie, cookie_len); + + ret = flap_sendpkt(handle, 0x01, packet, 0); + pkt_free(packet); + return ret; +} + +/* PROTO */ +void +handle_srv_migration(void *handle, uint8_t * data, uint16_t len) +{ + TLVLIST *tlv, *trav; + uint16_t num_family, cookie_len = 0; + pkt_t *inpkt; + int status = 0; + char *bos_server = 0; + uint8_t *cookie = 0; + + inpkt = pkt_initP(data + 10, len - 10); + + num_family = pkt_get16(inpkt); + if (num_family != 0 && num_family != ((IMCOMM *) handle)->num_families) { + printf("migration has different number of families.\n"); + printf("not proceeding (bifurcated?)\n"); + return; + } + pkt_freeP(inpkt); + + if (((IMCOMM *) handle)->srv_pause) + ((IMCOMM *) handle)->srv_pause = 0; + + tlv = + tlv_split(data + 12 + (num_family * 2), + len - (12 + (num_family * 2)), 0); + + printf("migration beginning.\n"); + + for (trav = tlv; trav != NULL; trav = trav->next) { + if (trav->type == 0x0005) { + bos_server = malloc(trav->len + 1); + memcpy(bos_server, trav->value, trav->len); + bos_server[trav->len] = 0; + status++; + } else if (trav->type == 0x0006) { + cookie = malloc(trav->len); + cookie_len = trav->len; + memcpy(cookie, trav->value, trav->len); + status++; + } + } + + clear_tlv_list(tlv); + + printf("server: %s\n", bos_server); + + if (((IMCOMM *) handle)->callbacks[IMCOMM_ERROR]) + ((IMCOMM *) handle)->callbacks[IMCOMM_ERROR] (handle, + IMCOMM_STATUS_MIGRATIONDONE); + + bos_signon_phase2(handle, (unsigned char *) bos_server, cookie, + cookie_len); + free(bos_server); + free(cookie); +} + +#ifdef MD5_LOGIN + +#define AIM_MD5_STRING "AOL Instant Messenger (SM)" + +/* + * New stuff for MD5-based login + */ + +/* PROTO */ +void +bos_md5snac(void *handle, uint8_t * data, uint16_t len) +{ + uint8_t *authkey; + uint16_t authkeylen; + md5_state_t state; + md5_byte_t auth_hash[16]; + pkt_t *packet; + + if (data[3] == 0x07) { + const char client_ident[] = CLIENT_IDENT; + + authkeylen = two_to_16(data + 10); + authkey = malloc(authkeylen); + memcpy(authkey, data + 12, authkeylen); + + md5_init(&state); + md5_append(&state, (const md5_byte_t *) authkey, authkeylen); + md5_append(&state, (const md5_byte_t *) ((IMCOMM *) handle)->pw, + strlen(((IMCOMM *) handle)->pw)); + md5_append(&state, (const md5_byte_t *) AIM_MD5_STRING, + strlen(AIM_MD5_STRING)); + md5_finish(&state, auth_hash); + + free(authkey); + + packet = + pkt_init(67 + strlen(CLIENT_IDENT) + 16 + + strlen(((IMCOMM *) handle)->sn)); + + /* + * I should really build a TLV here instead, but this works. + */ + + /* + * Add SN length + SN + */ + pkt_add16(packet, 0x0001); + pkt_add16(packet, (uint16_t) strlen(((IMCOMM *) handle)->sn)); + pkt_addraw(packet, (uint8_t *) ((IMCOMM *) handle)->sn, + strlen(((IMCOMM *) handle)->sn)); + pkt_add16(packet, 0x0025); + pkt_add16(packet, 0x0010); + pkt_addraw(packet, (uint8_t *) auth_hash, 16); + + + /* + * Add client ident string + */ + pkt_add16(packet, 0x0003); + pkt_add16(packet, (uint16_t) strlen(client_ident)); + pkt_addraw(packet, (uint8_t *) client_ident, strlen(client_ident)); + /* + * Add client ID (hardcoded) + */ + pkt_add16(packet, 0x0016); + pkt_add16(packet, 0x0002); + pkt_add16(packet, 0x0109); + + /* + * Add client versions (hardcoded) + */ + pkt_add16(packet, 0x0017); + pkt_add16(packet, 0x0002); + pkt_add16(packet, 0x0005); + pkt_add16(packet, 0x0018); + pkt_add16(packet, 0x0002); + pkt_add16(packet, 0x0005); + pkt_add16(packet, 0x0019); + pkt_add16(packet, 0x0002); + pkt_add16(packet, 0x0000); + pkt_add16(packet, 0x001A); + pkt_add16(packet, 0x0002); + pkt_add16(packet, 0x0e0b); + pkt_add16(packet, 0x0014); + pkt_add16(packet, 0x0004); + pkt_add32(packet, 0x00000104); + pkt_add16(packet, 0x000F); + pkt_add16(packet, 0x0002); + pkt_addraw(packet, (unsigned char *) "en", 2); + pkt_add16(packet, 0x000E); + pkt_add16(packet, 0x0002); + pkt_addraw(packet, (unsigned char *) "us", 2); + pkt_add16(packet, 0x004A); + pkt_add16(packet, 0x0001); + pkt_add8(packet, 0x01); + + snac_sendpkt(handle, 0x17, 0x02, packet, 0); + pkt_free(packet); + return; + } else if (data[3] == 0x03) { + TLVLIST *tlv, *trav; + uint16_t numtlv, cookie_len = 0; + int status = 0; + char *bos_server = 0; + uint8_t *cookie = 0; + + numtlv = count_tlv(data + 10, len - 10); + tlv = tlv_split(data + 10, len - 10, numtlv); + + for (trav = tlv; trav != NULL; trav = trav->next) { + if (trav->type == 0x0008) { + if (((IMCOMM *) handle)->callbacks[IMCOMM_ERROR]) + ((IMCOMM *) handle)->callbacks[IMCOMM_ERROR] (handle, + IMCOMM_ERROR_INVALID_LOGIN); +#ifdef MACINTOSH_CLASSIC + +#else + shutdown(((IMCOMM *) handle)->socket, 0x02); + ((IMCOMM *) handle)->socket = -1; +#endif + } else if (trav->type == 0x0005) { + bos_server = malloc(trav->len + 1); + memcpy(bos_server, trav->value, trav->len); + bos_server[trav->len] = 0; + status++; + } else if (trav->type == 0x0006) { + cookie = malloc(trav->len); + cookie_len = trav->len; + memcpy(cookie, trav->value, trav->len); + status++; + } + } + + clear_tlv_list(tlv); + + if (status == 2) { + if (((IMCOMM *) handle)->callbacks[IMCOMM_ERROR]) + ((IMCOMM *) handle)->callbacks[IMCOMM_ERROR] (handle, + IMCOMM_STATUS_AUTHDONE); + bos_signon_phase2(handle, (unsigned char *) bos_server, cookie, + cookie_len); + free(bos_server); + free(cookie); + } + } +} + +#endif /* MD5_LOGIN */ diff --git a/libs/libimcomm/byteswap.h b/libs/libimcomm/byteswap.h new file mode 100644 index 0000000..7461f7a --- /dev/null +++ b/libs/libimcomm/byteswap.h @@ -0,0 +1,7 @@ +#define BYTE_SWAP_16(x) (((x & 0xFF00) >> 8) | \ + ((x & 0x00FF) << 8)) + +#define BYTE_SWAP_32(x) (((x & 0xFF000000) >> 24) | \ + ((x & 0x00FF0000) >> 8) | \ + ((x & 0x0000FF00) << 8) | \ + ((x & 0x000000FF) << 24)) diff --git a/libs/libimcomm/flap.c b/libs/libimcomm/flap.c new file mode 100644 index 0000000..d769627 --- /dev/null +++ b/libs/libimcomm/flap.c @@ -0,0 +1,490 @@ +/** _ + ** (_)_ __ __ ___ _ __ _ __ + ** | | ' \/ _/ _ \ ' \| ' \ + ** |_|_|_|_\__\___/_|_|_|_|_|_| + ** + ** Copyright (C) 2003-2005, Claudio Leite + ** All rights reserved. + ** + ** Please see the file 'COPYING' for licensing information. + **/ + +#include "imcomm.h" + +extern int endianness; + +#ifdef MACINTOSH_CLASSIC +extern short refnum; + +OSErr +mactcp_recv(void *handle, char *inbuf, size_t len) +{ + TCPiopb pb; + OSErr err; + size_t dataRead = 0; + + pb.ioCRefNum = refnum; + pb.csCode = TCPRcv; + pb.tcpStream = ((IMCOMM *) handle)->s; + pb.csParam.receive.commandTimeoutValue = 2; + pb.csParam.receive.rcvBuff = inbuf; + pb.csParam.receive.rcvBuffLen = len; + pb.csParam.receive.userDataPtr = (Ptr) handle; + err = PBControlSync((ParmBlkPtr) & pb); + if (err != noErr) + return err; + + return noErr; +} +#endif + +#ifndef SEND_QUEUES +/* PROTO */ +IMCOMM_RET +flap_send(void *handle, uint8_t channel, unsigned char *packet, size_t len, int updateidle) +{ + pkt_t *outpacket; + size_t totallen; +#ifdef MACINTOSH_CLASSIC + TCPiopb pb; + wdsEntry wds[2]; + OSErr err; +#endif + + totallen = len + 6; + outpacket = pkt_init(totallen); + + pkt_add8(outpacket, 0x2A); + pkt_add8(outpacket, channel); + pkt_add16(outpacket, ((IMCOMM *) handle)->seqnum); + pkt_add16(outpacket, (uint16_t) len); + pkt_addraw(outpacket, packet, len); + +#ifdef MACINTOSH_CLASSIC + wds[0].length = outpacket->len; + wds[0].ptr = (char *) outpacket->data; + wds[1].length = 0; + + pb.ioCRefNum = refnum; + pb.csCode = TCPSend; + pb.tcpStream = ((IMCOMM *) handle)->s; + pb.csParam.send.validityFlags = 0; + pb.csParam.send.pushFlag = TRUE; + pb.csParam.send.urgentFlag = 0; + pb.csParam.send.wdsPtr = (Ptr) wds; + pb.csParam.send.userDataPtr = (Ptr) handle; + err = PBControlSync((ParmBlkPtr) & pb); +#else + if (send + (((IMCOMM *) handle)->socket, outpacket->data, outpacket->len, + 0) < 0) { + pkt_free(outpacket); + return IMCOMM_RET_ERROR; + } +#endif + + if (((IMCOMM *) handle)->seqnum < 0xFFFF) + ((IMCOMM *) handle)->seqnum++; + else + ((IMCOMM *) handle)->seqnum = 0; + + if (updateidle == 1) { + ((IMCOMM *) handle)->last_operation_time = time(NULL); + if (((IMCOMM *) handle)->isidle == 1) + imcomm_set_idle_time(handle, 0); + } + pkt_free(outpacket); + return IMCOMM_RET_OK; +} + +/* PROTO */ +struct MultiPacket * +MultiPktInit(void) +{ + struct MultiPacket *npkt; + + npkt = malloc(sizeof(struct MultiPacket)); + npkt->init = -1; + return npkt; +} + +/* PROTO */ +void +MultiPktFree(struct MultiPacket * h) +{ + struct MultiPacket *trav, *tmp; + + for (trav = h; trav != NULL;) { + free(trav->packet); + tmp = trav; + trav = trav->next; + free(tmp); + } +} + +/* PROTO */ +void +flap_addToMulti(struct MultiPacket * mpkt, uint8_t channel, unsigned char *packet, size_t len, int updateidle) +{ + struct MultiPacket *trav, *npkt; + int first; + + if (mpkt->init == -1) { + npkt = mpkt; + first = 1; + } else { + npkt = malloc(sizeof(struct MultiPacket)); + first = 0; + } + + npkt->channel = channel; + npkt->packet = malloc(len); + memcpy(npkt->packet, packet, len); + npkt->len = len; + npkt->updateidle = updateidle; + npkt->next = NULL; + npkt->init = 1; + + if (!first) { + for (trav = mpkt; trav->next != NULL; trav = trav->next); + trav->next = npkt; + } +} + +/* PROTO */ +IMCOMM_RET +flap_sendMulti(void *handle, struct MultiPacket * pktlist) +{ + pkt_t *outpacket; + size_t totallen; + struct MultiPacket *trav; + int updateidle = 0; +#ifdef MACINTOSH_CLASSIC + TCPiopb pb; + wdsEntry wds[2]; + OSErr err; +#endif + + for (trav = pktlist, totallen = 0; trav != NULL; trav = trav->next) { + totallen += 6 + trav->len; + if (trav->updateidle == 1) + updateidle = 1; + } + + outpacket = pkt_init(totallen); + + for (trav = pktlist; trav != NULL; trav = trav->next) { + pkt_add8(outpacket, 0x2A); + pkt_add8(outpacket, trav->channel); + pkt_add16(outpacket, ((IMCOMM *) handle)->seqnum); + pkt_add16(outpacket, (uint16_t) trav->len); + pkt_addraw(outpacket, trav->packet, trav->len); + + if (((IMCOMM *) handle)->seqnum < 0xFFFF) + ((IMCOMM *) handle)->seqnum++; + else + ((IMCOMM *) handle)->seqnum = 0; + } + +#ifdef MACINTOSH_CLASSIC + wds[0].length = outpacket->len; + wds[0].ptr = (char *) outpacket->data; + wds[1].length = 0; + + pb.ioCRefNum = refnum; + pb.csCode = TCPSend; + pb.tcpStream = ((IMCOMM *) handle)->s; + pb.csParam.send.validityFlags = 0; + pb.csParam.send.pushFlag = TRUE; + pb.csParam.send.urgentFlag = 0; + pb.csParam.send.wdsPtr = (Ptr) wds; + pb.csParam.send.userDataPtr = (Ptr) handle; + err = PBControlSync((ParmBlkPtr) & pb); +#else + if (send + (((IMCOMM *) handle)->socket, outpacket->data, outpacket->len, + 0) < 0) { + pkt_free(outpacket); + return IMCOMM_RET_ERROR; + } +#endif + if (updateidle == 1) { + ((IMCOMM *) handle)->last_operation_time = time(NULL); + if (((IMCOMM *) handle)->isidle == 1) + imcomm_set_idle_time(handle, 0); + } + pkt_free(outpacket); + return IMCOMM_RET_OK; +} + +#else +/* PROTO */ +IMCOMM_RET +flap_sendAct(void *handle, uint8_t channel, unsigned char *packet, size_t len, int updateidle) +{ + pkt_t *outpacket; + size_t totallen; +#ifdef MACINTOSH_CLASSIC + TCPiopb pb; + wdsEntry wds[2]; + OSErr err; +#endif + + totallen = len + 6; + outpacket = pkt_init(totallen); + + pkt_add8(outpacket, 0x2A); + pkt_add8(outpacket, channel); + pkt_add16(outpacket, ((IMCOMM *) handle)->seqnum); + pkt_add16(outpacket, (uint16_t) len); + pkt_addraw(outpacket, packet, len); + +#ifdef MACINTOSH_CLASSIC + wds[0].length = outpacket->len; + wds[0].ptr = (char *) outpacket->data; + wds[1].length = 0; + + pb.ioCRefNum = refnum; + pb.csCode = TCPSend; + pb.tcpStream = ((IMCOMM *) handle)->s; + pb.csParam.send.validityFlags = 0; + pb.csParam.send.pushFlag = TRUE; + pb.csParam.send.urgentFlag = 0; + pb.csParam.send.wdsPtr = (Ptr) wds; + pb.csParam.send.userDataPtr = (Ptr) handle; + err = PBControlSync((ParmBlkPtr) & pb); +#else + if (send + (((IMCOMM *) handle)->socket, outpacket->data, outpacket->len, + 0) < 0) { + pkt_free(outpacket); + return IMCOMM_RET_ERROR; + } +#endif + + if (((IMCOMM *) handle)->seqnum < 0xFFFF) + ((IMCOMM *) handle)->seqnum++; + else + ((IMCOMM *) handle)->seqnum = 0; + + if (updateidle == 1) { + ((IMCOMM *) handle)->last_operation_time = time(NULL); + if (((IMCOMM *) handle)->isidle == 1) + imcomm_set_idle_time(handle, 0); + } + pkt_free(outpacket); + return IMCOMM_RET_OK; +} + +/* PROTO */ +IMCOMM_RET +flap_sendnext(void *handle) +{ + IMCOMM_RET ret = IMCOMM_RET_OK; + send_q *nq, *head = ((IMCOMM *) handle)->s_queue; + + if (head) { + ret = + flap_sendAct(handle, head->channel, head->data, head->len, + head->updateidle); + nq = head; + head = head->next; + ((IMCOMM *) handle)->s_queue = head; + free(nq->data); + free(nq); + } + return ret; +} + +IMCOMM_RET +flap_send(void *handle, uint8_t channel, unsigned char *packet, size_t len, int updateidle) +{ + send_q *nq, *trav, *head = ((IMCOMM *) handle)->s_queue; + + nq = malloc(sizeof(struct IMCommSendQ)); + nq->next = NULL; + nq->updateidle = updateidle; + nq->data = malloc(len); + nq->channel = channel; + memcpy(nq->data, packet, len); + nq->len = len; + + if (head == NULL) { + ((IMCOMM *) handle)->s_queue = nq; + } else { + for (trav = head; trav->next != NULL; trav = trav->next); + + trav->next = nq; + } + + return IMCOMM_RET_OK; +} +#endif /* SEND_QUEUES */ + +/* PROTO */ +IMCOMM_RET +flap_sendpkt(void *handle, uint8_t channel, pkt_t * pkt, int updateidle) +{ + return flap_send(handle, channel, pkt->data, pkt->len, updateidle); +} + +/* PROTO */ +IMCOMM_RET +flap_decode(void *handle, unsigned char *header, unsigned char *data) +{ + pkt_t *packet; +#ifdef DEBUG + int y, z; + int x; +#endif + uint16_t len, sn_len; + uint16_t family, subfamily; + unsigned char *sn = NULL; + IMCOMM_RET ret = IMCOMM_RET_OK; +#ifdef DUMP + FILE *dump; + int xx; + dump = fopen("imcomm.dump", "a"); +#endif + + memcpy(&len, header + 4, 2); + if (endianness == HOST_LITTLE_ENDIAN) + len = BYTE_SWAP_16(len); + + packet = pkt_initP(data, len); + +#ifdef DUMP + for (xx = 0; x < 6; xx++) + fputc(header[xx], dump); + + for (xx = 0; x < len; xx++) + fputc(data[xx], dump); + + fclose(dump); +#endif + +#ifdef DEBUG + printf("Packet length: %u\n", (unsigned int) packet->len); + + for (x = 0, y = 0; x < len; x++) { + printf("%02X ", data[x]); + y++; + if (y == 16) { + for (y = 15; y >= 0; y--) { + if (data[x - y] > 31 && data[x - y] < 128) + putchar(data[x - y]); + else + putchar('.'); + } + printf("\n"); + y = 0; + } + } + + if (y < 16) { + for (z = 0; z < (16 - y); z++) + printf(" "); + while (y > 0) { + if (data[x - y] > 31 && data[x - y] < 128) + putchar(data[x - y]); + else + putchar('.'); + y--; + } + printf("\n"); + } + printf("\n"); +#endif + + switch (header[1]) { + case 0x02: + ret = snac_decode(handle, data, len); + break; + case 0x04: + family = pkt_get16(packet); + + if (family == 0x0009) { + subfamily = pkt_get16(packet); + if (subfamily == 0x0002) { + if (((IMCOMM *) handle)->callbacks[IMCOMM_ERROR]) + ((IMCOMM *) handle)->callbacks[IMCOMM_ERROR] (handle, + IMCOMM_ERROR_OTHER_SIGNON); +#ifdef MACINTOSH_CLASSIC + +#else + shutdown(((IMCOMM *) handle)->socket, 2); + ((IMCOMM *) handle)->socket = -1; +#endif + break; + } + } else if (family == 0x0001) { + + /* + * SRV_COOKIE + */ + + sn_len = pkt_get16(packet); + sn = pkt_getstr(packet, sn_len); + + if (((IMCOMM *) handle)->callbacks[IMCOMM_FORMATTED_SN]) + ((IMCOMM *) handle)-> + callbacks[IMCOMM_FORMATTED_SN] (handle, sn); + subfamily = pkt_get16(packet); + + switch (subfamily) { + case 0x0005: + { + unsigned char *server, *cookie; + uint16_t server_len, cookie_len; + + server_len = pkt_get16(packet); + server = pkt_getstr(packet, server_len); + + subfamily = pkt_get16(packet); +#ifdef DEBUG + if (subfamily != 0x0006) { + printf("WARNING: Cookie family not 0x0006!\n"); + } +#endif + + cookie_len = pkt_get16(packet); + cookie = pkt_getstr(packet, cookie_len); + + if (((IMCOMM *) handle)->callbacks[IMCOMM_ERROR]) + ((IMCOMM *) handle)-> + callbacks[IMCOMM_ERROR] (handle, + IMCOMM_STATUS_AUTHDONE); + ret = + bos_signon_phase2(handle, server, cookie, + cookie_len); + free(server); + free(cookie); + } + break; + case 0x0008: + case 0x0004: + if (((IMCOMM *) handle)->callbacks[IMCOMM_ERROR]) + ((IMCOMM *) handle)->callbacks[IMCOMM_ERROR] (handle, + IMCOMM_ERROR_INVALID_LOGIN); +#ifdef MACINTOSH_CLASSIC + +#else + shutdown(((IMCOMM *) handle)->socket, 0x02); + ((IMCOMM *) handle)->socket = -1; +#endif + break; + } + } + break; + } + + if (sn != NULL) + free(sn); + + /* + * This'll also free the incoming data buffer + */ + pkt_free(packet); + + return ret; +} diff --git a/libs/libimcomm/imcomm.c b/libs/libimcomm/imcomm.c new file mode 100644 index 0000000..539546c --- /dev/null +++ b/libs/libimcomm/imcomm.c @@ -0,0 +1,770 @@ +/** _ + ** (_)_ __ __ ___ _ __ _ __ + ** | | ' \/ _/ _ \ ' \| ' \ + ** |_|_|_|_\__\___/_|_|_|_|_|_| + ** + ** Copyright (C) 2003-2005, Claudio Leite + ** All rights reserved. + ** + ** Please see the file 'COPYING' for licensing information. + **/ + +#include "imcomm.h" + +IMCOMM_HANDLES *handles = NULL; +int endianness; +int nodes_to_delete = 0; + +#ifdef MACINTOSH_CLASSIC +extern short refnum; +#endif + +/* PROTO */ +void * +imcomm_create_handle(void) +{ + IMCOMM *handle; + IMCOMM_HANDLES *tmp; + int xx; + + handle = malloc(sizeof(IMCOMM)); + handle->proxymode = PROXY_TYPE_NONE; + handle->proxyserver = NULL; + handle->proxyport = 0; + + handle->to_delete = 0; + handle->ischild = 0; + handle->seqnum = 0x1000; + handle->snacreq = 0; + handle->families = NULL; + handle->num_families = 0; + handle->buddylist = NULL; + handle->buddies_online = NULL; + handle->isidle = 0; + handle->isinvisible = 0; + handle->last_operation_time = time(NULL); + handle->profile_str = NULL; + handle->away_msg = NULL; + handle->icondata = 0; + handle->iconlen = 0; + handle->socket = 0; + handle->connected = 0; + handle->srv_pause = 0; + handle->data = NULL; + handle->header_pos = 0; + handle->oscarport = 5190; +#ifdef MD5_LOGIN + handle->pw = NULL; + handle->sn = NULL; +#endif + +#ifdef IMCOMM_KEEPALIVE + handle->last_keepalive_time = 0; +#endif +#ifdef SEND_QUEUES + handle->s_queue = NULL; +#endif + +#ifdef MACINTOSH_CLASSIC + handle->readable = 0; +#endif + + endianness = getbyteorder(); + + for (xx = 0; xx < NUM_CALLBACKS; xx++) + handle->callbacks[xx] = NULL; + + if (handles == NULL) { + handles = malloc(sizeof(IMCOMM_HANDLES)); + handles->handle = handle; + handles->next = NULL; + } else { + tmp = handles; + + while (tmp->next != NULL) + tmp = tmp->next; + + tmp->next = malloc(sizeof(IMCOMM_HANDLES)); + tmp->next->handle = handle; + tmp->next->next = NULL; + } + return (void *) handle; +} + +/* PROTO */ +int +imcomm_delete_handle_now(void *vhandle) +{ + IMCOMM_HANDLES *tmp, *tr; + + if (handles == NULL) + return 0; + + if (handles->handle == (IMCOMM *) vhandle) { + tmp = handles; + handles = handles->next; + + imcomm_delete_handle_only((void *) tmp->handle); + free(tmp); + } else { + for (tr = handles; tr;) { + if (tr->handle == (IMCOMM *) vhandle) { + tmp = tr; + tr = tr->next; + + imcomm_delete_handle_only((void *) tmp->handle); + free(tmp); + continue; + } + tr = tr->next; + } + + } + + return 1; +} + +/* PROTO */ +int +imcomm_delete_handle(void *vhandle) +{ + ((IMCOMM *) vhandle)->to_delete = 1; + nodes_to_delete = 1; + + return 1; +} + +/* PROTO */ +int +imcomm_delete_handle_only(void *vhandle) +{ + IMCOMM *handle = (IMCOMM *) vhandle; + + if (handle->buddylist) + imcomm_delete_buddylist(handle->buddylist); + if (handle->buddies_online) + imcomm_delete_buddylist(handle->buddies_online); + if (handle->families) + imcomm_delete_familieslist(handle->families); + + if (handle->profile_str) + free(handle->profile_str); + if (handle->away_msg) + free(handle->away_msg); + if (handle->icondata) + free(handle->icondata); + if (handle->data) + free(handle->data); +#ifdef MD5_LOGIN + if (handle->sn) + free(handle->sn); + if (handle->pw) + free(handle->pw); +#endif + if (handle->proxyserver) + free(handle->proxyserver); + + if (handle->socket != -1) + shutdown(handle->socket, 0x02); + + free(vhandle); + + return 1; +} + +/* PROTO */ +void +imcomm_delete_buddylist(struct IMComm_BuddyList * buddylist) +{ + struct IMComm_BuddyList *tr, *tmp; + + for (tr = buddylist; tr;) { + if (tr->sn) + free(tr->sn); + if (tr->formattedsn) + free(tr->formattedsn); + + tmp = tr; + tr = tr->next; + + free(tmp); + } +} + +/* PROTO */ +void +imcomm_delete_familieslist(struct IMComm_Families * families) +{ + struct IMComm_Families *tr, *tmp; + + for (tr = families; tr;) { + tmp = tr; + tr = tr->next; + free(tmp); + } + +} + +/* PROTO */ +void +imcomm_set_oscar_port(void *handle, uint16_t port) +{ + ((IMCOMM *) handle)->oscarport = port; +} + +/* PROTO */ +void * +imcomm_create_child_handle(void *parent) +{ + IMCOMM *handle; + IMCOMM_HANDLES *tmp; + int xx; + + handle = malloc(sizeof(IMCOMM)); + + handle->ischild = 1; + handle->proxymode = ((IMCOMM *) parent)->proxymode; + handle->proxyserver = ((IMCOMM *) parent)->proxyserver; + handle->proxyport = ((IMCOMM *) parent)->proxyport; + handle->parent = parent; + handle->to_delete = 0; + handle->seqnum = 0x1000; + handle->snacreq = 0; + handle->families = NULL; + handle->buddylist = NULL; + handle->buddies_online = NULL; + handle->isidle = 0; + handle->last_operation_time = time(NULL); + handle->profile_str = NULL; + handle->away_msg = NULL; + handle->icondata = 0; + handle->iconlen = 0; + handle->socket = 0; + handle->connected = 0; + handle->data = NULL; + handle->header_pos = 0; +#ifdef IMCOMM_KEEPALIVE + handle->last_keepalive_time = 0; +#endif +#ifdef SEND_QUEUES + handle->s_queue = NULL; +#endif + +#ifdef MACINTOSH_CLASSIC + handle->readable = 0; +#endif + + for (xx = 0; xx < NUM_CALLBACKS; xx++) + handle->callbacks[xx] = ((IMCOMM *) parent)->callbacks[xx]; + + if (handles == NULL) { + handles = malloc(sizeof(IMCOMM_HANDLES)); + handles->handle = handle; + handles->next = NULL; + } else { + tmp = handles; + + while (tmp->next != NULL) + tmp = tmp->next; + + tmp->next = malloc(sizeof(IMCOMM_HANDLES)); + tmp->next->handle = handle; + tmp->next->next = NULL; + } + return (void *) handle; +} + +/* PROTO */ +void +remove_deleted_handles(void) +{ + IMCOMM_HANDLES *trav, *tmp; + + if (handles == NULL) + return; + + if (handles->handle->to_delete == 1) { + + /* + * the last thing it'll do before deleting itself is to send + * a callback saying it's about to be deleted. + */ + + if (handles->handle->callbacks[IMCOMM_HANDLE_DELETED]) + handles->handle-> + callbacks[IMCOMM_HANDLE_DELETED] ((void *) handles-> + handle); + + tmp = handles; + handles = handles->next; + + imcomm_delete_handle_only(tmp->handle); + + free(tmp); + + remove_deleted_handles(); + } else { + for (trav = handles; trav->next;) { + if (trav->next->handle->to_delete == 1) { + tmp = trav->next; + trav->next = trav->next->next; + trav = trav->next; + + if (tmp->handle->callbacks[IMCOMM_HANDLE_DELETED]) + tmp->handle-> + callbacks[IMCOMM_HANDLE_DELETED] ((void *) tmp-> + handle); + + imcomm_delete_handle_only(tmp->handle); + free(tmp); + } + } + } +} + +/* PROTO */ +void +imcomm_set_proxy(void *handle, int type, char *proxyserver, uint16_t proxyport) +{ + ((IMCOMM *) handle)->proxymode = type; + ((IMCOMM *) handle)->proxyserver = strdup(proxyserver); + ((IMCOMM *) handle)->proxyport = proxyport; +} + +/* PROTO */ +void +imcomm_register_callback(void *handle, int event, void (*ptr) ()) +{ + ((IMCOMM *) handle)->callbacks[event] = ptr; +} + +/* PROTO */ +IMCOMM_RET +imcomm_select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval * timeout) +{ + IMCOMM_HANDLES *tmp; + IMCOMM_RET ret = IMCOMM_RET_OK; + int maxfd = nfds; +#ifdef FULL_PACKET_AT_ONCE + int bytesread; +#endif + + /* + * trim the handle list + */ + if (nodes_to_delete == 1) { + remove_deleted_handles(); + nodes_to_delete = 0; + } + tmp = handles; + +#ifdef MACINTOSH_CLASSIC + TCPiopb pb; + OSErr err; + + for (tmp = handles; tmp != NULL; tmp = tmp->next) { + if (tmp->handle->readable == 0) + continue; + + pb.ioCRefNum = refnum; + pb.csCode = TCPStatus; + pb.tcpStream = tmp->handle->s; + pb.csParam.status.userDataPtr = (Ptr) tmp->handle; + err = PBControlSync((ParmBlkPtr) & pb); + if (err != noErr) + continue; + + if (pb.csParam.status.amtUnreadData >= 6) { + mactcp_recv(tmp->handle, (char *) tmp->handle->header, 6); + tmp->handle->data_len = two_to_16(tmp->handle->header + 4); + tmp->handle->data = malloc(tmp->handle->data_len); + mactcp_recv(tmp->handle, (char *) tmp->handle->data, + tmp->handle->data_len); + ret = + flap_decode(tmp->handle, tmp->handle->header, + tmp->handle->data); + tmp->handle->data = NULL; + } + } +#else + while (tmp != NULL) { + if ((int) tmp->handle->socket > maxfd) + maxfd = tmp->handle->socket; + if (tmp->handle->socket != -1) + FD_SET(tmp->handle->socket, readfds); + tmp = tmp->next; + } + + if (select(maxfd + 1, readfds, writefds, exceptfds, timeout) == -1) + return IMCOMM_RET_ERROR; + + for (tmp = handles; tmp; tmp = tmp->next) { + if (tmp->handle->socket == -1) + continue; + +#ifdef SEND_QUEUES + if (tmp->handle->s_queue != NULL) + flap_sendnext(tmp->handle); +#endif + + if (FD_ISSET(tmp->handle->socket, readfds)) { +#ifdef FULL_PACKET_AT_ONCE + bytesread = 0; + do { + if ((bytesread += + recv(tmp->handle->socket, + tmp->handle->header + bytesread, 6 - bytesread, + 0)) <= 0) { + shutdown(tmp->handle->socket, 0x02); + tmp->handle->socket = -1; + tmp->handle->data = NULL; + tmp->handle->connected = 0; + if (tmp->handle->callbacks[IMCOMM_ERROR]) + tmp->handle->callbacks[IMCOMM_ERROR] (tmp->handle, + IMCOMM_ERROR_DISCONNECTED); + return IMCOMM_RET_ERROR; + } + } while (bytesread < 6); + + tmp->handle->data_len = two_to_16(tmp->handle->header + 4); + tmp->handle->data = malloc(tmp->handle->data_len); + bytesread = 0; + do { + if ((bytesread += + recv(tmp->handle->socket, + tmp->handle->data + bytesread, + tmp->handle->data_len - bytesread, 0)) <= 0) { + shutdown(tmp->handle->socket, 0x02); + tmp->handle->socket = -1; + tmp->handle->connected = 0; + tmp->handle->data = NULL; + if (tmp->handle->callbacks[IMCOMM_ERROR]) + tmp->handle->callbacks[IMCOMM_ERROR] (tmp->handle, + IMCOMM_ERROR_DISCONNECTED); + return IMCOMM_RET_ERROR; + } + } while (bytesread < tmp->handle->data_len); + + ret = + flap_decode(tmp->handle, tmp->handle->header, + tmp->handle->data); + tmp->handle->data = NULL; +#else + if (tmp->handle->header_pos < 6) { + if (recv + (tmp->handle->socket, + &tmp->handle->header[tmp->handle->header_pos], 1, + 0) <= 0) { + shutdown(tmp->handle->socket, 0x02); + tmp->handle->socket = -1; + tmp->handle->connected = 0; + tmp->handle->header_pos = 0; + tmp->handle->data = NULL; + if (tmp->handle->callbacks[IMCOMM_ERROR]) + tmp->handle->callbacks[IMCOMM_ERROR] (tmp->handle, + IMCOMM_ERROR_DISCONNECTED); + return IMCOMM_RET_ERROR; + } + tmp->handle->header_pos++; + if (tmp->handle->header_pos == 6) { + tmp->handle->data_len = + two_to_16(tmp->handle->header + 4); + tmp->handle->data = malloc(tmp->handle->data_len); + tmp->handle->data_pos = 0; + } + } else { + if (recv + (tmp->handle->socket, + &tmp->handle->data[tmp->handle->data_pos], 1, + 0) <= 0) { + free(tmp->handle->data); + tmp->handle->data = NULL; + shutdown(tmp->handle->socket, 0x02); + tmp->handle->socket = -1; + tmp->handle->connected = 0; + tmp->handle->header_pos = 0; + if (tmp->handle->callbacks[IMCOMM_ERROR]) + tmp->handle->callbacks[IMCOMM_ERROR] (tmp->handle, + IMCOMM_ERROR_DISCONNECTED); + return IMCOMM_RET_ERROR; + } + tmp->handle->data_pos++; + if (tmp->handle->data_pos == tmp->handle->data_len) { + ret = + flap_decode(tmp->handle, tmp->handle->header, + tmp->handle->data); + tmp->handle->data = NULL; + tmp->handle->header_pos = 0; + } + } +#endif + } + /* + * This seems to slow down the DOS port on slower machines, + * so let's get rid of it... + */ +#ifdef IMCOMM_KEEPALIVE + if (time(NULL) - tmp->handle->last_keepalive_time > 300) { + tmp->handle->last_keepalive_time = time(NULL); + if (tmp->handle->srv_pause == 0) + flap_send(tmp->handle, 0x05, NULL, 0, 0); + } +#endif + +#if !defined(__DJGPP__) && !defined(NO_AUTO_IDLE) + imcomm_set_idle_time(tmp->handle, + time(NULL) - + tmp->handle->last_operation_time); +#endif + } +#endif + return ret; +} + +/* PROTO */ +int +imcomm_internal_add_buddy(void *handle, char *sn, const unsigned long idletime, const unsigned long onlinetime, int isaway) +{ + IMCOMM_BUDDYLIST *temp, *trav; + char *sname; + + sname = imcomm_simplify_sn(sn); + + for (trav = ((IMCOMM *) handle)->buddies_online; trav != NULL; + trav = trav->next) { + if (strcmp(sname, trav->sn) == 0) { + free(sname); + return 0; + } + } + + temp = malloc(sizeof(IMCOMM_BUDDYLIST)); + temp->sn = sname; + temp->formattedsn = NULL; + temp->next = NULL; + temp->isaway = isaway; + temp->idletime = idletime; + temp->onlinetime = onlinetime; + + if (((IMCOMM *) handle)->buddies_online == NULL) + ((IMCOMM *) handle)->buddies_online = temp; + else { + for (trav = ((IMCOMM *) handle)->buddies_online; + trav->next != NULL; trav = trav->next); + + trav->next = temp; + } + + return 1; +} + +/* PROTO */ +void +imcomm_update_buddy_times(void *handle, const char *sn, int type, unsigned long value) +{ + IMCOMM_BUDDYLIST *trav = ((IMCOMM *) handle)->buddies_online; + char *sname; + + sname = imcomm_simplify_sn(sn); + + for (; trav != NULL; trav = trav->next) { + if (strcmp(sname, trav->sn) == 0) { + switch (type) { + case 1: + trav->idletime = value; + if (((IMCOMM *) handle)->callbacks[IMCOMM_IM_IDLEINFO]) + ((IMCOMM *) handle)-> + callbacks[IMCOMM_IM_IDLEINFO] (handle, sn, value); + break; + case 2: + trav->onlinetime = value; + break; + } + } + } + free(sname); +} + +/* PROTO */ +void +imcomm_update_buddy_away(void *handle, const char *sn, int isaway) +{ + char *sname; + IMCOMM_BUDDYLIST *trav = ((IMCOMM *) handle)->buddies_online; + + sname = imcomm_simplify_sn(sn); + + for (; trav != NULL; trav = trav->next) { + if (strcmp(sname, trav->sn) == 0) { + if (isaway) { + if (!trav->isaway) { + trav->isaway = 1; + if (((IMCOMM *) handle)-> + callbacks[IMCOMM_IM_BUDDYAWAY]) + ((IMCOMM *) handle)-> + callbacks[IMCOMM_IM_BUDDYAWAY] (handle, sn); + break; + } + } else if (trav->isaway) { + trav->isaway = 0; + if (((IMCOMM *) handle)->callbacks[IMCOMM_IM_BUDDYUNAWAY]) + ((IMCOMM *) handle)-> + callbacks[IMCOMM_IM_BUDDYUNAWAY] (handle, sn); + break; + } + } + } + + free(sname); +} + +/* PROTO */ +void +imcomm_internal_delete_buddy(void *handle, const char *sn) +{ + char *sname; + IMCOMM_BUDDYLIST *temp, *trav; + + if (((IMCOMM *) handle)->buddies_online == NULL) + return; + + sname = imcomm_simplify_sn(sn); + + if (strcmp(((IMCOMM *) handle)->buddies_online->sn, sname) == 0) { + temp = ((IMCOMM *) handle)->buddies_online; + ((IMCOMM *) handle)->buddies_online = + ((IMCOMM *) handle)->buddies_online->next; + free(temp->sn); + free(temp); + free(sname); + } else { + for (trav = ((IMCOMM *) handle)->buddies_online; + trav->next != NULL; trav = trav->next) { + if (strcmp(trav->next->sn, sname) == 0) { + temp = trav->next; + trav->next = trav->next->next; + free(temp->sn); + free(temp); + free(sname); + break; + } + } + } +} + +/* PROTO */ +char * +imcomm_simplify_sn(const char *sn) +{ + char *temp; + int x, count; + + temp = malloc(strlen(sn) + 1); + for (x = 0, count = 0; x < (int) strlen(sn); x++) { + if (sn[x] == ' ') + continue; + temp[count] = tolower(sn[x]); + count++; + } + + temp = realloc(temp, count + 1); + temp[count] = 0; + return temp; +} + +/* PROTO */ +void +imcomm_set_idle_time(void *handle, uint32_t idlesecs) +{ + pkt_t *packet; + packet = pkt_init(4); + + pkt_add32(packet, idlesecs); + + if (idlesecs > 600) { + if (((IMCOMM *) handle)->isidle == 0) { + ((IMCOMM *) handle)->isidle = 1; + snac_sendpkt(handle, 0x01, 0x11, packet, 0); + } + } else { + if (((IMCOMM *) handle)->isidle && idlesecs == 0) { + ((IMCOMM *) handle)->isidle = 0; + snac_sendpkt(handle, 0x01, 0x11, packet, 0); + } + } + + pkt_free(packet); +} + +/* PROTO */ +void +imcomm_set_profile(void *handle, char *profile) +{ + if (((IMCOMM *) handle)->profile_str != NULL) + free(((IMCOMM *) handle)->profile_str); + + ((IMCOMM *) handle)->profile_str = (unsigned char *) strdup(profile); + if (((IMCOMM *) handle)->socket != 0) + snac_set_location_info(handle); +} + +/* PROTO */ +void +imcomm_set_invisible(void *handle, int inv) +{ + ((IMCOMM *) handle)->isinvisible = inv; + snac_send_cli_update(handle); +} + +/* PROTO */ +void +imcomm_set_away(void *handle, char *msg) +{ + IMCOMM *tmp = (IMCOMM *) handle; + + tmp->isaway = 1; + tmp->away_msg = (unsigned char *) strdup(msg); + if (tmp->socket != 0) + snac_set_location_info(handle); +} + +/* PROTO */ +void +imcomm_set_unaway(void *handle) +{ + IMCOMM *tmp = (IMCOMM *) handle; + + if (tmp->isaway) { + free(tmp->away_msg); + tmp->isaway = 0; + tmp->away_msg = NULL; + if (tmp->socket != 0) + snac_set_location_info(handle); + } +} + +/* PROTO */ +int +imcomm_compare_nicks(void *handle, const char *s1, const char *s2) +{ + char *s3, *s4; + int ret = 0; + + s3 = imcomm_simplify_sn(s1); + s4 = imcomm_simplify_sn(s2); + + if (strcmp(s3, s4) == 0) + ret = 1; + + free(s3); + free(s4); + + return ret; +} + +/* PROTO */ +uint16_t +imcomm_get_max_message_size(void *handle) +{ + return ((IMCOMM *) handle)->max_message_size; +} diff --git a/libs/libimcomm/imcomm.h b/libs/libimcomm/imcomm.h new file mode 100644 index 0000000..b373135 --- /dev/null +++ b/libs/libimcomm/imcomm.h @@ -0,0 +1,311 @@ +/** _ + ** (_)_ __ __ ___ _ __ _ __ + ** | | ' \/ _/ _ \ ' \| ' \ + ** |_|_|_|_\__\___/_|_|_|_|_|_| + ** + ** Copyright (C) 2003-2005, Claudio Leite + ** All rights reserved. + ** + ** Please see the file 'COPYING' for licensing information. + **/ + +#ifndef IMCOMM_H +#define IMCOMM_H + +#ifdef PLAN9 +#define _POSIX_SOURCE +#define _BSD_EXTENSION +#define _POSIX_EXTENSION +#include + +/** + ** On 386, this is correct. This may not be + ** correct on other architectures. + **/ + +#define uint32_t unsigned long +#define uint16_t unsigned short +#define uint8_t unsigned char +#define int32_t long +#endif + +#include +#include +#ifdef _MSC_VER +#define snprintf _snprintf +#else +#include +#endif + +#if defined(WATCOM_WIN32) || defined(_MSC_VER) +#define __MINGW32__ /* works for now */ +#endif + +#ifdef MACINTOSH_CLASSIC +#include +#include +#include +#include +#else +#ifndef __MINGW32__ +#include +#include +#include +#include +#ifndef __BEOS__ +#include +#endif +#include +#else +#include + +#ifdef _MSC_VER +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef __int8 int8_t; +typedef unsigned __int8 uint8_t; +#else +#include +#endif + +#include +#endif +#endif + +#ifdef __BEOS__ +#include +#endif + +#define MD5_LOGIN + +#ifdef MACINTOSH_CLASSIC +typedef void fd_set; +typedef unsigned long uint32_t; +typedef unsigned short uint16_t; +typedef unsigned char uint8_t; +char *strdup(char *); +char *strcasecmp(char *, char *); +void mactcp_close(void *handle); +OSErr mactcp_recv(void *handle, char *inbuf, size_t len); +#endif + +#ifdef __AMIGA__ +#define uint32_t u_int32_t +#define uint16_t u_int16_t +#define uint8_t u_int8_t +#endif + +/* + * Read the whole packet at once rather than one byte at a time. + * + * This is necessary for DOS, but all other platforms seem to be OK with reading + * one byte at a time. + * + * UPDATED 0.80: I'm making this the default. I have yet to see an instance + * where this is unacceptable, but yet I've seen plenty of occasions where + * not having it slows old machines down considerably. + * + * Full packet may be frustrating on slow connections? + */ +#define FULL_PACKET_AT_ONCE + +#ifndef __DJGPP__ +#define IMCOMM_KEEPALIVE +#endif + +#define NO_AUTO_IDLE + +#ifdef linux +#include +#endif + +#if defined(__APPLE__) || defined(linux) +#include +#endif + +#include +#include + +#define HOST_BIG_ENDIAN 0 +#define HOST_LITTLE_ENDIAN 1 + +#ifdef __DJGPP__ +#ifndef __dj_stdint__h_ +typedef unsigned long uint32_t; +typedef unsigned short uint16_t; +typedef unsigned char uint8_t; +#endif +#endif + +typedef int IMCOMM_RET; + +#define IMCOMM_RET_ERROR -1 +#define IMCOMM_RET_OK 1 + +#define NUM_CALLBACKS 11 +enum { + IMCOMM_IM_SIGNON, + IMCOMM_IM_SIGNOFF, + IMCOMM_IM_BUDDYAWAY, + IMCOMM_IM_BUDDYUNAWAY, + IMCOMM_IM_IDLEINFO, + IMCOMM_IM_INCOMING, + IMCOMM_IM_PROFILE, + IMCOMM_IM_AWAYMSG, + IMCOMM_ERROR, + IMCOMM_FORMATTED_SN, + IMCOMM_HANDLE_DELETED +}; + +enum { + PROXY_TYPE_NONE, + PROXY_TYPE_HTTPS, + PROXY_TYPE_SOCKS5 +}; + +enum { + PROXY_ERROR_AUTH, + PROXY_ERROR_CONNECT, + PROXY_ERROR_PROXYCONNECT, + PROXY_ERROR_UNKNOWN +}; + +enum { + IMCOMM_ERROR_DISCONNECTED, + IMCOMM_STATUS_CONNECTED, + IMCOMM_ERROR_INVALID_LOGIN, + IMCOMM_ERROR_OTHER_SIGNON, + IMCOMM_STATUS_AUTHDONE, + IMCOMM_RATE_LIMIT_WARN, + IMCOMM_WARN_PAUSE, + IMCOMM_WARN_UNPAUSE, + IMCOMM_STATUS_MIGRATIONDONE, + IMCOMM_ERROR_USER_OFFLINE, + IMCOMM_ERROR_PROXY +}; + +#ifdef SEND_QUEUES +typedef struct IMCommSendQ { + unsigned char *data; + size_t len; + int updateidle; + uint8_t channel; + struct IMCommSendQ *next; +} send_q; +#endif + +typedef struct IMComm { +#ifdef MACINTOSH_CLASSIC + StreamPtr s; + int readable; +#endif +#ifdef __MINGW32__ + WSADATA wsadata; + SOCKET socket; +#else + int socket; +#endif +#ifdef MD5_LOGIN + char *sn; + char *pw; +#endif + + int proxymode; + char *proxyserver; + uint16_t proxyport; + + uint16_t oscarport; + + unsigned char header[6]; + uint8_t header_pos; + unsigned char *data; + uint16_t data_pos; + uint16_t data_len; + int connected; + int srv_pause; + int to_delete; + uint16_t seqnum; + uint32_t snacreq; + uint16_t max_profile_len; + uint16_t max_capabilities; + uint16_t max_buddylist_size; + uint16_t max_num_watchers; + uint16_t max_online_notifications; + uint16_t max_message_size; + uint16_t max_sender_warning; + uint16_t max_receiver_warning; + uint16_t max_message_interval; + uint16_t max_visible_list_size; + uint16_t max_invisible_list_size; + /* void (*callbacks[NUM_CALLBACKS]) (void *,...); */ + void (*callbacks[NUM_CALLBACKS]) (); + struct IMComm_Families *families; + int num_families; + struct IMComm_BuddyList *buddylist; + struct IMComm_BuddyList *buddies_online; + int isidle; + int isaway; + int isinvisible; + long last_operation_time; + unsigned char *profile_str; + unsigned char *away_msg; +#ifdef IMCOMM_KEEPALIVE + long last_keepalive_time; +#endif +#ifdef SEND_QUEUES + send_q *s_queue; +#endif + int ischild; + void *parent; + uint8_t *icondata; + uint16_t iconlen; +} IMCOMM; + +typedef struct IMComm_Families { + uint16_t family; + struct IMComm_Families *next; +} IMCOMM_FAMILIES; + +typedef struct IMComm_BuddyList { + char *sn; + char *formattedsn; + unsigned long idletime; + unsigned long onlinetime; + uint16_t ssi_id; + uint16_t group_id; + int isaway; + struct IMComm_BuddyList *next; +} IMCOMM_BUDDYLIST; + +typedef struct IMComm_Handles { + IMCOMM *handle; + struct IMComm_Handles *next; +} IMCOMM_HANDLES; + +typedef struct TLVList { + uint16_t type; + uint16_t len; + uint8_t *value; + struct TLVList *next; +} TLVLIST; + +typedef struct IMComm_Packet { + unsigned char *data; + size_t len; + size_t offset; +} pkt_t; + +struct MultiPacket { + int init; + uint8_t channel; + unsigned char *packet; + size_t len; + int updateidle; + struct MultiPacket *next; +}; + +#include "protos.h" +#include "byteswap.h" +#endif diff --git a/libs/libimcomm/makeprotos-sed b/libs/libimcomm/makeprotos-sed new file mode 100644 index 0000000..421fbac --- /dev/null +++ b/libs/libimcomm/makeprotos-sed @@ -0,0 +1,18 @@ +# Get prototypes from a .c file +# $Id: makeprotos-sed,v 1.1.1.1 2004/07/19 14:32:40 leitec Exp $ +# /* PROTO */ must be above return type which are above function. +# Args are on one line +# eg. +# /* PROTO */ +# void ------> void main(int argc, char **argv); +# main(int argc, char **argv) +# { +# } +# +/^[/][*] PROTO [*][/]$/{ +n +N +s/\n\([_a-zA-Z][_a-zA-Z0-9]* *\)(/ \1 (/ +s/$/;/ +p +} diff --git a/libs/libimcomm/md5.c b/libs/libimcomm/md5.c new file mode 100644 index 0000000..7c772de --- /dev/null +++ b/libs/libimcomm/md5.c @@ -0,0 +1,394 @@ +/* + * NOTE: I changed "int" to "int32_t" across the board, plus the changes + * indicated in md5.h + * + * Claudio Leite + */ + +/* + * Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from + * the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not claim + * that you wrote the original software. If you use this software in a + * product, an acknowledgment in the product documentation would be + * appreciated but is not required. 2. Altered source versions must be + * plainly marked as such, and must not be misrepresented as being the + * original software. 3. This notice may not be removed or altered from any + * source distribution. + * + * L. Peter Deutsch ghost@aladdin.com + * + */ +/* $Id: md5.c,v 1.8 2007/09/15 14:52:24 leitec Exp $ */ +/* + * Independent implementation of MD5 (RFC 1321). + * + * This code implements the MD5 Algorithm defined in RFC 1321, whose text is + * available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from + * the text of the RFC, including the test suite (section A.5) but excluding + * the rest of Appendix A. It does not include any code or documentation + * that is identified in the RFC as being copyrighted. + * + * The original and principal author of md5.c is L. Peter Deutsch + * . Other authors are noted in the change history that + * follows (in reverse chronological order): + * + * 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + * either statically or dynamically; added missing #include in + * library. 2002-03-11 lpd Corrected argument list for main(), and added int + * return type, in test program and T value program. 2002-02-21 lpd Added + * missing #include in test program. 2000-07-03 lpd Patched to + * eliminate warnings about "constant is unsigned in ANSI C, signed in + * traditional"; made test program self-checking. 1999-11-04 lpd Edited + * comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo + * in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original + * version. + */ + +#include "md5.h" +#include + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = + * unknown */ +#ifdef ARCH_IS_BIG_ENDIAN +#define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +#define BYTE_ORDER 0 +#endif + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + + +static void +md5_process(md5_state_t * pms, const md5_byte_t * data /* [64] */ ) +{ + md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = + pms->abcd[3]; + md5_word_t t; +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X; +#endif + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int32_t w = 1; + + if (*((const md5_byte_t *) & w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly + * aligned data without copying it. + */ + if (!((data - (const md5_byte_t *) 0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *) data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes + * in the right order. + */ + const md5_byte_t *xp = data; + int32_t i; + +#if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +#else +#define xbuf X /* (static only) */ +#endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = + xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* + * Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + + * X[k] + T[i]) <<< s). + */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* + * Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + + * X[k] + T[i]) <<< s). + */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* + * Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + + * X[k] + T[i]) <<< s). + */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* + * Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + + * X[k] + T[i]) <<< s). + */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* + * Then perform the following additions. (That is increment each of + * the four registers by the value it had before this block was + * started.) + */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t * pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /* 0xefcdab89 */ T_MASK ^ 0x10325476; + pms->abcd[2] = /* 0x98badcfe */ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t * pms, const md5_byte_t * data, int32_t nbytes) +{ + const md5_byte_t *p = data; + int32_t left = nbytes; + int32_t offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t) (nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int32_t copy = + (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t * pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int32_t i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t) (pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t) (pms->abcd[i >> 2] >> ((i & 3) << 3)); +} diff --git a/libs/libimcomm/md5.h b/libs/libimcomm/md5.h new file mode 100644 index 0000000..0386332 --- /dev/null +++ b/libs/libimcomm/md5.h @@ -0,0 +1,98 @@ +/* + * NOTE: + * + * I've changed some of the int types around to match the rest of the IMcomm + * source. + * + * -Claudio Leite + */ + +/* + * Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from + * the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not claim + * that you wrote the original software. If you use this software in a + * product, an acknowledgment in the product documentation would be + * appreciated but is not required. 2. Altered source versions must be + * plainly marked as such, and must not be misrepresented as being the + * original software. 3. This notice may not be removed or altered from any + * source distribution. + * + * L. Peter Deutsch ghost@aladdin.com + * + */ +/* $Id: md5.h,v 1.8 2007/09/15 14:52:24 leitec Exp $ */ +/* + * Independent implementation of MD5 (RFC 1321). + * + * This code implements the MD5 Algorithm defined in RFC 1321, whose text is + * available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from + * the text of the RFC, including the test suite (section A.5) but excluding + * the rest of Appendix A. It does not include any code or documentation + * that is identified in the RFC as being copyrighted. + * + * The original and principal author of md5.h is L. Peter Deutsch + * . Other authors are noted in the change history that + * follows (in reverse chronological order): + * + * 2002-04-13 lpd Removed support for non-ANSI compilers; removed references to + * Ghostscript; clarified derivation from RFC 1321; now handles byte order + * either statically or dynamically. 1999-11-04 lpd Edited comments slightly + * for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment + * (ansi2knr rather than md5); added conditionalization for C++ compilation + * from Martin Purschke . 1999-05-03 lpd Original version. + */ + +#ifndef md5_INCLUDED +#define md5_INCLUDED + +/* added by Claudio Leite */ +#include "imcomm.h" +/* end */ + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef uint8_t md5_byte_t; /* 8-bit byte */ +typedef uint32_t md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4];/* digest buffer */ + md5_byte_t buf[64];/* accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" { +#endif + + /* Initialize the algorithm. */ + void md5_init(md5_state_t * pms); + + /* Append a string to the message. */ + void md5_append(md5_state_t * pms, const md5_byte_t * data, + int32_t nbytes); + + /* Finish the message and return the digest. */ + void md5_finish(md5_state_t * pms, md5_byte_t digest[16]); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif +#endif /* md5_INCLUDED */ diff --git a/libs/libimcomm/misc.c b/libs/libimcomm/misc.c new file mode 100644 index 0000000..51e9673 --- /dev/null +++ b/libs/libimcomm/misc.c @@ -0,0 +1,25 @@ +/** _ + ** (_)_ __ __ ___ _ __ _ __ + ** | | ' \/ _/ _ \ ' \| ' \ + ** |_|_|_|_\__\___/_|_|_|_|_|_| + ** + ** Copyright (C) 2003-2005, Claudio Leite + ** All rights reserved. + ** + ** Please see the file 'COPYING' for licensing information. + **/ + +#include "imcomm.h" + +/* PROTO */ +int +getbyteorder(void) +{ + uint16_t blah = 0x5533; + uint8_t *ptr = (uint8_t *) & blah; + + if ((*ptr) == 0x55) + return HOST_BIG_ENDIAN; + else + return HOST_LITTLE_ENDIAN; +} diff --git a/libs/libimcomm/mkprotos b/libs/libimcomm/mkprotos new file mode 100644 index 0000000..8d99263 --- /dev/null +++ b/libs/libimcomm/mkprotos @@ -0,0 +1,6 @@ +#!/bin/sh + +rm -f protos.h +for i in *.c; do + sed -n -f ./makeprotos-sed $i >> protos.h +done diff --git a/libs/libimcomm/packet.c b/libs/libimcomm/packet.c new file mode 100644 index 0000000..5ddb540 --- /dev/null +++ b/libs/libimcomm/packet.c @@ -0,0 +1,303 @@ +/** _ + ** (_)_ __ __ ___ _ __ _ __ + ** | | ' \/ _/ _ \ ' \| ' \ + ** |_|_|_|_\__\___/_|_|_|_|_|_| + ** + ** Copyright (C) 2003-2005, Claudio Leite + ** All rights reserved. + ** + ** Please see the file 'COPYING' for licensing information. + **/ + +/* + * packet.c + * + * Contains the packet code. This is inspired by FAIM's bstream code, and will + * resolve the portability problems caused by my shoddy allocations in + * previous versions. + * + * Basically, instead of doing everything manually by using assignment + * statements like: unsigned char packet[] = {0x00, 0x01, 0x03} or + * packet[pos++] = 0x04; we define a packet dynamically, allocating memory + * once (pkt_init) and then creating a separate function for each data type + * to be added, with a "raw" function for any unhandled data. + * + * This is mostly because the older code didn't compile on basically anything + * but GCC. When I came around to porting to Macintosh, it became apparent + * that my nasty code had to change! + */ + +#include "imcomm.h" +#include + +extern int endianness; + +/* + * Create an empty packet. + */ + +/* PROTO */ +pkt_t * +pkt_init(size_t len) +{ + pkt_t *pkt = NULL; + + pkt = malloc((size_t) sizeof(struct IMComm_Packet)); + pkt->data = malloc(len); + pkt->len = len; + pkt->offset = 0; + + return pkt; +} + +/* PROTO */ +void +pkt_zero(pkt_t * pkt) +{ + assert(pkt != NULL); + + memset(pkt->data, 0, pkt->len); +} + +/* PROTO */ +void +pkt_free(pkt_t * pkt) +{ + assert(pkt != NULL); + + if (pkt->data != NULL) { + free(pkt->data); + } + free(pkt); +} + +/* PROTO */ +void +pkt_freeP(pkt_t * pkt) +{ + assert(pkt != NULL); + + /* don't touch the data */ + free(pkt); +} + + +/* + * This points the data to an already initialized buffer (say, a received + * packet) instead of copying data. + */ + +/* PROTO */ +pkt_t * +pkt_initP(uint8_t * data, uint16_t len) +{ + pkt_t *pkt; + + pkt = malloc(sizeof(struct IMComm_Packet)); + pkt->data = data; + pkt->len = (size_t) len; + pkt->offset = 0; + + return pkt; +} + +/* PROTO */ +size_t +pkt_empty(pkt_t * pkt) +{ + return pkt->len - pkt->offset; +} + +/* PROTO */ +size_t +pkt_getoffset(pkt_t * pkt) +{ + return pkt->offset; +} + +/* PROTO */ +void +pkt_skip(pkt_t * pkt, size_t skipnum) +{ + /* assert(pkt->offset + skipnum < pkt->len); */ + pkt->offset += skipnum; +} + +/* PROTO */ +void +pkt_setoffset(pkt_t * pkt, size_t offset) +{ + assert(offset < pkt->len); + pkt->offset = offset; +} + +/* PROTO */ +int +pkt_end(pkt_t * pkt) +{ + if (pkt->offset >= pkt->len) + return 1; + else + return 0; +} + +/* PROTO */ +IMCOMM_RET +pkt_add8(pkt_t * pkt, uint8_t data) +{ + if (pkt_empty(pkt) < 1) + return IMCOMM_RET_ERROR; + + memcpy(pkt->data + pkt->offset, &data, 1); + pkt->offset++; + return IMCOMM_RET_OK; +} + +/* + * AIM is big-endian. + * + * Endianness is determined at startup and stored in a global var. + */ + +/* PROTO */ +IMCOMM_RET +pkt_add16(pkt_t * pkt, uint16_t val) +{ + uint16_t tmpval; + + if (pkt_empty(pkt) < 2) + return IMCOMM_RET_ERROR; + + if (endianness == HOST_BIG_ENDIAN) { + memcpy(pkt->data + pkt->offset, &val, 2); + } else { + tmpval = BYTE_SWAP_16(val); + memcpy(pkt->data + pkt->offset, &tmpval, 2); + } + + pkt->offset += 2; + return IMCOMM_RET_OK; +} + +/* PROTO */ +IMCOMM_RET +pkt_add32(pkt_t * pkt, uint32_t val) +{ + uint32_t tmpval; + + if (pkt_empty(pkt) < 4) + return IMCOMM_RET_ERROR; + + if (endianness == HOST_BIG_ENDIAN) { + memcpy(pkt->data + pkt->offset, &val, 4); + } else { + tmpval = BYTE_SWAP_32(val); + memcpy(pkt->data + pkt->offset, &tmpval, 4); + } + + pkt->offset += 4; + return IMCOMM_RET_OK; +} + +/* PROTO */ +IMCOMM_RET +pkt_addraw(pkt_t * pkt, uint8_t * data, size_t len) +{ + if (pkt_empty(pkt) < len) + return IMCOMM_RET_ERROR; + + memcpy(pkt->data + pkt->offset, data, len); + pkt->offset += len; + return IMCOMM_RET_OK; +} + +/* PROTO */ +uint8_t +pkt_get8(pkt_t * pkt) +{ + uint8_t val; + + memcpy(&val, pkt->data + pkt->offset, 1); + pkt->offset++; + return val; +} + +/* PROTO */ +uint16_t +pkt_get16(pkt_t * pkt) +{ + uint16_t val; + + memcpy(&val, pkt->data + pkt->offset, 2); + + if (endianness == HOST_LITTLE_ENDIAN) + val = BYTE_SWAP_16(val); + + pkt->offset += 2; + return val; +} + +/* PROTO */ +uint32_t +pkt_get32(pkt_t * pkt) +{ + uint32_t val; + + memcpy(&val, pkt->data + pkt->offset, 4); + + if (endianness == HOST_LITTLE_ENDIAN) + val = BYTE_SWAP_32(val); + + pkt->offset += 4; + return val; +} + +/* PROTO */ +uint8_t * +pkt_getraw(pkt_t * pkt, size_t len) +{ + uint8_t *buf; + + buf = malloc(len); + memcpy(buf, pkt->data + pkt->offset, len); + + pkt->offset += (uint16_t) len; + + return buf; +} + +/* PROTO */ +uint8_t * +pkt_getstr(pkt_t * pkt, size_t len) +{ + uint8_t *buf; + + buf = malloc(len + 1); + memcpy(buf, pkt->data + pkt->offset, len); + pkt->offset += (uint16_t) len; + buf[len] = 0; + return buf; +} + +#ifdef DEBUG +/* PROTO */ +void +pkt_dump(pkt_t * pkt) +{ + int x; + + printf("!! "); + for (x = 0; x < pkt->len; x++) { + if (pkt->data[x] >= 32 && pkt->data[x] < 128) + putchar(pkt->data[x]); + else + putchar('.'); + } + + printf("\n!! "); + for (x = 0; x < pkt->len; x++) + printf("%02X ", pkt->data[x]); + + printf("\n"); +} +#endif diff --git a/libs/libimcomm/protos.h b/libs/libimcomm/protos.h new file mode 100644 index 0000000..91d9cb1 --- /dev/null +++ b/libs/libimcomm/protos.h @@ -0,0 +1,109 @@ +#ifdef __cplusplus +extern "C" { +#endif + +IMCOMM_RET imcomm_im_signon(void *handle, const char *sn, const char *pw); +IMCOMM_RET bos_signon_phase2(void *handle, unsigned const char *server, unsigned const char *cookie, uint16_t cookie_len); +void handle_srv_migration(void *handle, uint8_t * data, uint16_t len); +void bos_md5snac(void *handle, uint8_t * data, uint16_t len); +IMCOMM_RET flap_send(void *handle, uint8_t channel, unsigned char *packet, size_t len, int updateidle); +struct MultiPacket *MultiPktInit(void); +void MultiPktFree(struct MultiPacket * h); +void flap_addToMulti(struct MultiPacket * mpkt, uint8_t channel, unsigned char *packet, size_t len, int updateidle); +IMCOMM_RET flap_sendMulti(void *handle, struct MultiPacket * pktlist); +IMCOMM_RET flap_sendAct(void *handle, uint8_t channel, unsigned char *packet, size_t len, int updateidle); +IMCOMM_RET flap_sendnext(void *handle); +IMCOMM_RET flap_sendpkt(void *handle, uint8_t channel, pkt_t * pkt, int updateidle); +IMCOMM_RET flap_decode(void *handle, unsigned char *header, unsigned char *data); +void *imcomm_create_handle(void); +int imcomm_delete_handle_now(void *vhandle); +int imcomm_delete_handle(void *vhandle); +int imcomm_delete_handle_only(void *vhandle); +void imcomm_delete_buddylist(struct IMComm_BuddyList * buddylist); +void imcomm_delete_familieslist(struct IMComm_Families * families); +void imcomm_set_oscar_port(void *handle, uint16_t port); +void *imcomm_create_child_handle(void *parent); +void remove_deleted_handles(void); +void imcomm_set_proxy(void *handle, int type, char *proxyserver, uint16_t proxyport); +void imcomm_register_callback(void *handle, int event, void (*ptr) ()); +IMCOMM_RET imcomm_select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval * timeout); +int imcomm_internal_add_buddy(void *handle, char *sn, const unsigned long idletime, const unsigned long onlinetime, int isaway); +void imcomm_update_buddy_times(void *handle, const char *sn, int type, unsigned long value); +void imcomm_update_buddy_away(void *handle, const char *sn, int isaway); +void imcomm_internal_delete_buddy(void *handle, const char *sn); +char *imcomm_simplify_sn(const char *sn); +void imcomm_set_idle_time(void *handle, uint32_t idlesecs); +void imcomm_set_profile(void *handle, char *profile); +void imcomm_set_invisible(void *handle, int inv); +void imcomm_set_away(void *handle, char *msg); +void imcomm_set_unaway(void *handle); +int imcomm_compare_nicks(void *handle, const char *s1, const char *s2); +uint16_t imcomm_get_max_message_size(void *handle); +int getbyteorder(void); +pkt_t *pkt_init(size_t len); +void pkt_zero(pkt_t * pkt); +void pkt_free(pkt_t * pkt); +void pkt_freeP(pkt_t * pkt); +pkt_t *pkt_initP(uint8_t * data, uint16_t len); +size_t pkt_empty(pkt_t * pkt); +size_t pkt_getoffset(pkt_t * pkt); +void pkt_skip(pkt_t * pkt, size_t skipnum); +void pkt_setoffset(pkt_t * pkt, size_t offset); +int pkt_end(pkt_t * pkt); +IMCOMM_RET pkt_add8(pkt_t * pkt, uint8_t data); +IMCOMM_RET pkt_add16(pkt_t * pkt, uint16_t val); +IMCOMM_RET pkt_add32(pkt_t * pkt, uint32_t val); +IMCOMM_RET pkt_addraw(pkt_t * pkt, uint8_t * data, size_t len); +uint8_t pkt_get8(pkt_t * pkt); +uint16_t pkt_get16(pkt_t * pkt); +uint32_t pkt_get32(pkt_t * pkt); +uint8_t *pkt_getraw(pkt_t * pkt, size_t len); +uint8_t *pkt_getstr(pkt_t * pkt, size_t len); +void pkt_dump(pkt_t * pkt); +int connect_socks5(void *handle, char *host, uint16_t port); +int connect_https(void *handle, char *host, uint16_t port); +IMCOMM_RET snac_decode(void *handle, uint8_t * data, uint16_t len); +void snac_addToMulti(void *handle, struct MultiPacket * mpkt, uint16_t family, uint16_t subtype, unsigned char *data, uint16_t len, int updateidle); +IMCOMM_RET snac_send(void *handle, uint16_t family, uint16_t subtype, unsigned char *data, uint16_t len, int updateidle); +IMCOMM_RET snac_sendpkt(void *handle, uint8_t family, uint8_t subtype, pkt_t * pkt, int updateidle); +IMCOMM_RET snac_send_versions(void *handle); +IMCOMM_RET snac_request_limits(void *handle); +IMCOMM_RET snac_ack_srv_pause(void *handle, uint8_t * data, size_t len); +IMCOMM_RET snac_get_srv_families(void *handle, uint8_t * data, size_t len); +IMCOMM_RET snac_ack_limits(void *handle, unsigned char *data, size_t len); +IMCOMM_RET snac_multireq(void *handle); +IMCOMM_RET snac_get_privacy_rights(void *handle, uint8_t * data, uint16_t len); +IMCOMM_RET snac_set_location_info(void *handle); +IMCOMM_RET snac_send_icbm_params(void *handle, uint16_t channel, uint16_t max_msg_size); +IMCOMM_RET snac_ssi_activate(void *handle); +IMCOMM_RET snac_ssi_get_list(void *handle, uint8_t * data, uint16_t len); +IMCOMM_RET snac_send_cli_update(void *handle); +IMCOMM_RET multi_ssiact_cliready(void *handle); +IMCOMM_RET snac_send_cli_ready(void *handle); +size_t count_tlv(unsigned char *data, size_t len); +size_t count_tlv_pkt(pkt_t * tp); +TLVLIST *tlv_split(unsigned char *data, size_t len, size_t numtlv); +void clear_tlv_list(TLVLIST * tlvlist); +uint32_t four_to_32(unsigned char *value); +uint16_t two_to_16(unsigned char *value); +IMCOMM_RET snac_get_incoming_im(void *handle, uint8_t * data, uint16_t len); +IMCOMM_RET snac_get_signoff(void *handle, uint8_t * data, uint16_t len); +IMCOMM_RET snac_get_signon(void *handle, uint8_t * data, uint16_t len); +void snac_get_user_info(void *handle, uint8_t * data, uint16_t len); +void imcomm_im_send_message(void *handle, const char *whom, const char *msg, int automsg); +void imcomm_request_awayprofile(void *handle, char *sn); +void imcomm_request_profile(void *handle, char *sn); +void imcomm_request_awaymsg(void *handle, char *sn); +void imcomm_request_massawaymsg(void *handle, char **sns, int num); +void imcomm_addtobuddylist(void *handle, char *sn, uint16_t id, uint16_t group_id); +uint16_t imcomm_get_next_id(void *handle); +void imcomm_im_add_buddy(void *handle, char *sn); +void imcomm_im_remove_buddy(void *handle, const char *sn); +void snac_request_new_service(void *handle, uint16_t service); +void snac_new_subconnection(void *handle, unsigned char *data, uint16_t len); +void imcomm_upload_icon(void *handle, uint8_t * data, uint16_t icon_len); +void snac_finish_buddy_icon(void *handle); + +#ifdef __cplusplus +} +#endif diff --git a/libs/libimcomm/proxy.c b/libs/libimcomm/proxy.c new file mode 100644 index 0000000..4a140f5 --- /dev/null +++ b/libs/libimcomm/proxy.c @@ -0,0 +1,227 @@ +/** _ + ** (_)_ __ __ ___ _ __ _ __ + ** | | ' \/ _/ _ \ ' \| ' \ + ** |_|_|_|_\__\___/_|_|_|_|_|_| + ** + ** Copyright (C) 2003-2005, Claudio Leite + ** All rights reserved. + ** + ** Please see the file 'COPYING' for licensing information. + **/ + +#include "imcomm.h" + +/* PROTO */ +int +connect_socks5(void *handle, char *host, uint16_t port) +{ + IMCOMM *h = (IMCOMM *) handle; + struct sockaddr_in sin; + struct hostent *he = NULL; + long addy; + struct in_addr ina = {0}; + pkt_t *sockspkt; + uint8_t len; + unsigned char sockbuf[512]; + +#ifdef DEBUG + printf("Connecting via SOCKS5 to %s/%u\n", host, port); + printf("SOCKS5 proxy server: %s/%u\n", h->proxyserver, h->proxyport); +#endif + + if ((he = gethostbyname(h->proxyserver)) == NULL) { + addy = inet_addr(h->proxyserver); + ina.s_addr = addy; + } + if ((h->socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + if (h->callbacks[IMCOMM_ERROR]) + h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_PROXY, + PROXY_ERROR_CONNECT); + + return IMCOMM_RET_ERROR; + } + sin.sin_family = AF_INET; + sin.sin_port = htons(h->proxyport); + + if (he == NULL) + sin.sin_addr = ina; + else + sin.sin_addr = *((struct in_addr *) he->h_addr); + + memset(&(sin.sin_zero), 0, 8); + + if (connect + (h->socket, (struct sockaddr *) & sin, + sizeof(struct sockaddr)) == -1) { + if (h->callbacks[IMCOMM_ERROR]) + h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_PROXY, + PROXY_ERROR_CONNECT); + + return IMCOMM_RET_ERROR; + } + sockspkt = pkt_init(3); + pkt_add8(sockspkt, 0x05); + pkt_add8(sockspkt, 0x01); + pkt_add8(sockspkt, 0x00); + + if (send(h->socket, sockspkt->data, sockspkt->len, 0) < 0) { + pkt_free(sockspkt); + if (h->callbacks[IMCOMM_ERROR]) + h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_DISCONNECTED, + 0); + + shutdown(h->socket, 0x02); + h->socket = -1; + return IMCOMM_RET_ERROR; + } + pkt_free(sockspkt); + + recv(h->socket, sockbuf, 2, 0); + if (sockbuf[1] != 0x00) { + if (h->callbacks[IMCOMM_ERROR]) + h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_PROXY, + PROXY_ERROR_AUTH); + return IMCOMM_RET_ERROR; + } + sockspkt = pkt_init(7 + strlen(host)); + pkt_add8(sockspkt, 0x05); + pkt_add8(sockspkt, 0x01); + pkt_add8(sockspkt, 0x00); + pkt_add8(sockspkt, 0x03); + pkt_add8(sockspkt, (uint8_t) strlen(host)); + pkt_addraw(sockspkt, (unsigned char *) host, strlen(host)); + pkt_add16(sockspkt, port); + + if (send(h->socket, sockspkt->data, sockspkt->len, 0) < 0) { + pkt_free(sockspkt); + if (h->callbacks[IMCOMM_ERROR]) + h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_DISCONNECTED, + 0); + + shutdown(h->socket, 0x02); + h->socket = -1; + return IMCOMM_RET_ERROR; + } + pkt_free(sockspkt); + + recv(h->socket, sockbuf, 4, 0); + if (sockbuf[1] != 0x00) { + if (h->callbacks[IMCOMM_ERROR]) + h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_PROXY, + PROXY_ERROR_PROXYCONNECT); + shutdown(h->socket, 0x02); + h->socket = -1; + + return IMCOMM_RET_ERROR; + } + if (sockbuf[3] == 0x03) { + recv(h->socket, &len, 1, 0); + recv(h->socket, sockbuf, len + 2, 0); + } else if (sockbuf[3] == 0x01) { + recv(h->socket, sockbuf, 6, 0); + } else { + if (h->callbacks[IMCOMM_ERROR]) + h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_PROXY, + PROXY_ERROR_UNKNOWN); + + shutdown(h->socket, 0x02); + h->socket = -1; + return IMCOMM_RET_ERROR; + } + + /* now we should be set to read the connection */ + + return IMCOMM_RET_OK; +} + +/* PROTO */ +int +connect_https(void *handle, char *host, uint16_t port) +{ + IMCOMM *h = (IMCOMM *) handle; + struct sockaddr_in sin; + struct hostent *he = NULL; + long addy; + struct in_addr ina = {0}; + unsigned char sockbuf[512]; + char *sptr; + int received, retcode; + +#ifdef DEBUG + printf("Connecting via HTTPS to %s/%d.\n", host, port); + printf("Proxy server: %s/%d\n", h->proxyserver, h->proxyport); +#endif + + if ((he = gethostbyname(h->proxyserver)) == NULL) { + addy = inet_addr(h->proxyserver); + ina.s_addr = addy; + } + if ((h->socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + if (h->callbacks[IMCOMM_ERROR]) + h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_PROXY, + PROXY_ERROR_CONNECT); + + return IMCOMM_RET_ERROR; + } + sin.sin_family = AF_INET; + sin.sin_port = htons(h->proxyport); + + if (he == NULL) + sin.sin_addr = ina; + else + sin.sin_addr = *((struct in_addr *) he->h_addr); + + memset(&(sin.sin_zero), 0, 8); + + if (connect + (h->socket, (struct sockaddr *) & sin, + sizeof(struct sockaddr)) == -1) { + if (h->callbacks[IMCOMM_ERROR]) + h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_PROXY, + PROXY_ERROR_CONNECT); + + return IMCOMM_RET_ERROR; + } + /* + * This user agent seems pretty well-accepted. Not sure if this is + * any sort of problem... + */ + + snprintf((char *) sockbuf, sizeof(sockbuf), + "CONNECT %s:%d HTTP/1.0\r\nUser-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01\r\n\r\n", + host, port); + if (send(h->socket, sockbuf, strlen((char *) sockbuf), 0) < 0) { + if (h->callbacks[IMCOMM_ERROR]) + h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_DISCONNECTED, + 0); + + shutdown(h->socket, 0x02); + h->socket = -1; + return IMCOMM_RET_ERROR; + } + received = recv(h->socket, sockbuf, sizeof(sockbuf), 0); + sockbuf[received] = 0; + + sptr = strchr((char *) sockbuf, ' '); + retcode = atoi(sptr + 1); + + if (retcode != 200) { + if (h->callbacks[IMCOMM_ERROR]) + h->callbacks[IMCOMM_ERROR] (handle, IMCOMM_ERROR_PROXY, + PROXY_ERROR_PROXYCONNECT); + + shutdown(h->socket, 0x02); + h->socket = -1; + + return IMCOMM_RET_ERROR; + } else { + while (strstr((char *) sockbuf, "\r\n\r\n") == NULL) { + received = recv(h->socket, sockbuf, sizeof(sockbuf), 0); + sockbuf[received] = 0; + } + } + + /* now we should be set to read the connection */ + + return IMCOMM_RET_OK; +} diff --git a/libs/libimcomm/snac.c b/libs/libimcomm/snac.c new file mode 100644 index 0000000..0da1f44 --- /dev/null +++ b/libs/libimcomm/snac.c @@ -0,0 +1,1433 @@ +/** _ + ** (_)_ __ __ ___ _ __ _ __ + ** | | ' \/ _/ _ \ ' \| ' \ + ** |_|_|_|_\__\___/_|_|_|_|_|_| + ** + ** Copyright (C) 2003-2005, Claudio Leite + ** All rights reserved. + ** + ** Please see the file 'COPYING' for licensing information. + **/ + +#include "imcomm.h" + +/* + * OK, by a little cleaning up, I mean a lot of cleaning up. + * + * I need to split this into several files and comment it. If anyone is brave + * enough to try to figure out this mess, go for it, but you've been warned. + */ + +/* + * This file could use a little cleaning up. + * + * A lot of this was hurried in an attempt to get a working client, but I never + * bothered to fix it since it worked. + */ + +extern int endianness; +extern int nodes_to_delete; + +/* PROTO */ +IMCOMM_RET +snac_decode(void *handle, uint8_t * data, uint16_t len) +{ + uint16_t family, subfamily, flags; + TLVLIST *tlvlist; + + if (len <= 4) + return IMCOMM_RET_OK; + + family = two_to_16(data); + subfamily = two_to_16(data + 2); + flags = two_to_16(data + 4); + + if (((IMCOMM *) handle)->ischild == 1) { + family = two_to_16(data); + subfamily = two_to_16(data + 2); + + if (family == 0x0001 && subfamily == 0x0003) { + if (data[12] == 0x00 && data[13] == 0x10) { + snac_finish_buddy_icon(handle); +#ifdef DEBUG + printf("sent buddy icon\n"); +#endif + return IMCOMM_RET_OK; + } + } else if (family == 0x0010 && subfamily == 0x0003) { + /* ack from buddy icon upload */ + ((IMCOMM *) handle)->to_delete = 1; + nodes_to_delete = 1; +#ifdef DEBUG + printf + ("Received ACK for buddy icon upload, marking handle for deletion.\n"); +#endif + return IMCOMM_RET_OK; + } else { + printf("not really parsing child.\n"); + return IMCOMM_RET_OK; + } + + return IMCOMM_RET_OK; + } +#ifdef MD5_LOGIN + if (family == 0x0017) { + bos_md5snac(handle, data, len); + return IMCOMM_RET_OK; + } +#endif + + if (family == 0x0001) { + char *sn; + uint8_t sn_len; + + switch (subfamily) { + /* + * supported families list respond with (01,17) + */ + case 0x0003: + snac_get_srv_families(handle, data + 10, len - 10); + return snac_send_versions(handle); + break; + /* + * we're not really worried about versions right now. + */ + case 0x0005: + snac_new_subconnection(handle, data + 18, len - 18); + return IMCOMM_RET_OK; + break; + case 0x0018: + return snac_request_limits(handle); + break; + case 0x0007: + return snac_ack_limits(handle, data + 10, len - 10); + break; + case 0x000a: + if (((IMCOMM *) handle)->callbacks[IMCOMM_ERROR]) { + ((IMCOMM *) handle)->callbacks[IMCOMM_ERROR] (handle, + IMCOMM_RATE_LIMIT_WARN, + data[19]); + } + break; +#if 0 + case 0x000b: + if (((IMCOMM *) handle)->callbacks[IMCOMM_ERROR]) { + ((IMCOMM *) handle)->callbacks[IMCOMM_ERROR] (handle, + IMCOMM_WARN_PAUSE); + } + return snac_ack_srv_pause(handle, data + 10, len - 10); + break; + case 0x000d: + if (((IMCOMM *) handle)->callbacks[IMCOMM_ERROR]) { + ((IMCOMM *) handle)->callbacks[IMCOMM_ERROR] (handle, + IMCOMM_WARN_UNPAUSE); + } + if (((IMCOMM *) handle)->srv_pause) + ((IMCOMM *) handle)->srv_pause = 0; + + break; +#endif + case 0x000f: + if (flags == 0x8000) + break; + + sn_len = data[10]; + sn = malloc(sn_len + 1); + memcpy(sn, data + 11, sn_len); + sn[sn_len] = 0; + + if (((IMCOMM *) handle)->callbacks[IMCOMM_FORMATTED_SN]) + ((IMCOMM *) handle)-> + callbacks[IMCOMM_FORMATTED_SN] (handle, sn); + + free(sn); + break; +#if 0 + case 0x0012: + handle_srv_migration(handle, data, len); + break; +#endif + } + } else if (family == 0x0002) { + switch (subfamily) { + case 0x0003: + ((IMCOMM *) handle)->max_profile_len = two_to_16(data + 14); + ((IMCOMM *) handle)->max_capabilities = two_to_16(data + 20); + if (snac_set_location_info(handle) == IMCOMM_RET_ERROR) + return IMCOMM_RET_ERROR; + else + return IMCOMM_RET_OK; + case 0x0006: + snac_get_user_info(handle, data + 10, len - 10); + return IMCOMM_RET_OK; + } + } else if (family == 0x0003) { + switch (subfamily) { + case 0x0003: + tlvlist = tlv_split(data + 10, len - 10, 3); + { + TLVLIST *trav; + for (trav = tlvlist; trav != NULL; trav = trav->next) { + switch (trav->type) { + case 0x01: + if (trav->len >= 2) + ((IMCOMM *) handle)->max_buddylist_size = + two_to_16(trav->value); + break; + case 0x02: + if (trav->len >= 2) + ((IMCOMM *) handle)->max_num_watchers = + two_to_16(trav->value); + break; + case 0x03: + if (trav->len >= 2) + ((IMCOMM *) handle)->max_online_notifications = + two_to_16(trav->value); + break; + } + } + } + clear_tlv_list(tlvlist); + return IMCOMM_RET_OK; + case 0x0C: + return snac_get_signoff(handle, data, len); + case 0x0B: + return snac_get_signon(handle, data, len); + } + } else if (family == 0x0004) { + switch (subfamily) { + case 0x0001: + if (data[11] == 0x04) { + if (((IMCOMM *) handle)->callbacks[IMCOMM_ERROR]) + ((IMCOMM *) handle)->callbacks[IMCOMM_ERROR] (handle, + IMCOMM_ERROR_USER_OFFLINE); + } + return IMCOMM_RET_OK; + case 0x0005: + ((IMCOMM *) handle)->max_message_size = two_to_16(data + 16); + ((IMCOMM *) handle)->max_sender_warning = two_to_16(data + 18); + ((IMCOMM *) handle)->max_receiver_warning = + two_to_16(data + 20); + ((IMCOMM *) handle)->max_message_interval = + two_to_16(data + 22); + return snac_send_icbm_params(handle, two_to_16(data + 10), + 1024); + case 0x0007: + return snac_get_incoming_im(handle, data, len); + } + } else if (family == 0x0009) { + switch (subfamily) { + case 0x0003: + return snac_get_privacy_rights(handle, data, len); + } + } else if (family == 0x0013) { + switch (subfamily) { + case 0x0006: + snac_ssi_get_list(handle, data, len); + return snac_ssi_activate(handle); + } + } + return IMCOMM_RET_OK; +} + +/* PROTO */ +void +snac_addToMulti(void *handle, struct MultiPacket * mpkt, uint16_t family, uint16_t subtype, unsigned char *data, uint16_t len, int updateidle) +{ + pkt_t *snac_packet; + + snac_packet = pkt_init(len + 10); + pkt_add16(snac_packet, family); + pkt_add16(snac_packet, subtype); + pkt_add16(snac_packet, 0); + pkt_add32(snac_packet, ((IMCOMM *) handle)->snacreq); + pkt_addraw(snac_packet, (uint8_t *) data, len); + ((IMCOMM *) handle)->snacreq++; + + flap_addToMulti(mpkt, 0x02, snac_packet->data, snac_packet->len, + updateidle); + pkt_free(snac_packet); +} + +/* PROTO */ +IMCOMM_RET +snac_send(void *handle, uint16_t family, uint16_t subtype, unsigned char *data, uint16_t len, int updateidle) +{ + pkt_t *snac_packet; + IMCOMM_RET ret; + + if (((IMCOMM *) handle)->srv_pause) + return IMCOMM_RET_OK; + + snac_packet = pkt_init(len + 10); + pkt_add16(snac_packet, family); + pkt_add16(snac_packet, subtype); + pkt_add16(snac_packet, 0); + pkt_add32(snac_packet, ((IMCOMM *) handle)->snacreq); + pkt_addraw(snac_packet, (uint8_t *) data, len); + ((IMCOMM *) handle)->snacreq++; + + ret = flap_sendpkt(handle, 0x02, snac_packet, updateidle); + pkt_free(snac_packet); + return ret; +} + +/* PROTO */ +IMCOMM_RET +snac_sendpkt(void *handle, uint8_t family, uint8_t subtype, pkt_t * pkt, int updateidle) +{ + return snac_send(handle, family, subtype, pkt->data, + (uint16_t) pkt->len, updateidle); +} + +/* PROTO */ +IMCOMM_RET +snac_send_versions(void *handle) +{ + /* + * I love it when I get really lazy... + * + * This works... + */ + unsigned char packet[] = + {0x00, 0x13, 0x00, 0x03, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, + 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x09, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x0C, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x04}; + + return snac_send(handle, 0x01, 0x17, packet, (uint16_t) sizeof(packet), + 0); +} + +/* PROTO */ +IMCOMM_RET +snac_request_limits(void *handle) +{ + return snac_send(handle, 0x01, 0x06, NULL, 0, 0); +} + +/* PROTO */ +IMCOMM_RET +snac_ack_srv_pause(void *handle, uint8_t * data, size_t len) +{ + pkt_t *ackpkt; + struct IMComm_Families *tr; + int count; + + for (count = 0, tr = ((IMCOMM *) handle)->families; tr; tr = tr->next) + count++; + + ackpkt = pkt_init(count * 2); /* each family is 16 bits */ + + for (tr = ((IMCOMM *) handle)->families; tr; tr = tr->next) { + pkt_add16(ackpkt, tr->family); + printf("adding family %d (total %d).\n", tr->family, count); + } + + ((IMCOMM *) handle)->srv_pause = 1; + + /* return snac_send(handle, 0x01, 0x0c, data, len, 0); */ + snac_sendpkt(handle, 0x01, 0x0c, ackpkt, 0); + + pkt_free(ackpkt); + + return IMCOMM_RET_OK; +} + +/* PROTO */ +IMCOMM_RET +snac_get_srv_families(void *handle, uint8_t * data, size_t len) +{ + struct IMComm_Families *lastptr; + pkt_t *inpkt = pkt_initP(data, len); + int num_families = 0; + + if (pkt_end(inpkt)) + return IMCOMM_RET_ERROR; + + ((IMCOMM *) handle)->families = malloc(sizeof(struct IMComm_Families)); + ((IMCOMM *) handle)->families->family = pkt_get16(inpkt); + num_families++; + + lastptr = ((IMCOMM *) handle)->families; + lastptr->next = NULL; + + while (!pkt_end(inpkt)) { + lastptr->next = malloc(sizeof(struct IMComm_Families)); + lastptr->next->family = pkt_get16(inpkt); + lastptr->next->next = NULL; + lastptr = lastptr->next; + num_families++; + } + + pkt_freeP(inpkt); + + ((IMCOMM *) handle)->num_families = num_families; + + return IMCOMM_RET_OK; +} + +/* PROTO */ +IMCOMM_RET +snac_ack_limits(void *handle, unsigned char *data, size_t len) +{ + pkt_t *pkt; + uint16_t x, y, num_classes, *ids; + + num_classes = two_to_16(data); + ids = malloc(num_classes * 2); /* it's a 16 bit type, so we need + * twice the bytes. Thanks to djgpp + * for catching this bug! UNIX/win32 + * let it go. */ + + + for (x = 2, y = 0; y < num_classes; y++) { + ids[y] = two_to_16(data + x); + x += 35; + } + + pkt = pkt_init(num_classes * 2); + + for (y = 0; y < num_classes; y++) + pkt_add16(pkt, ids[y]); + + if (snac_sendpkt(handle, 0x01, 0x08, pkt, 0) != IMCOMM_RET_OK) { + pkt_free(pkt); + free(ids); + return IMCOMM_RET_ERROR; + } + pkt_free(pkt); + free(ids); + + return snac_multireq(handle); +} + +/* PROTO */ +IMCOMM_RET +snac_multireq(void *handle) +{ + struct MultiPacket *mpkt; + + mpkt = MultiPktInit(); + + snac_addToMulti(handle, mpkt, 0x01, 0x0e, NULL, 0, 0); + snac_addToMulti(handle, mpkt, 0x13, 0x02, NULL, 0, 0); + snac_addToMulti(handle, mpkt, 0x13, 0x04, NULL, 0, 0); + snac_addToMulti(handle, mpkt, 0x02, 0x02, NULL, 0, 0); + snac_addToMulti(handle, mpkt, 0x03, 0x02, NULL, 0, 0); + snac_addToMulti(handle, mpkt, 0x04, 0x04, NULL, 0, 0); + snac_addToMulti(handle, mpkt, 0x09, 0x02, NULL, 0, 0); + + flap_sendMulti(handle, mpkt); + + MultiPktFree(mpkt); + return IMCOMM_RET_OK; +} + +/* PROTO */ +IMCOMM_RET +snac_get_privacy_rights(void *handle, uint8_t * data, uint16_t len) +{ + TLVLIST *tlvlist, *trav; + + tlvlist = tlv_split(data + 10, len - 10, 2); + + for (trav = tlvlist; trav != NULL; trav = trav->next) { + if (trav->type == 0x0001) { + ((IMCOMM *) handle)->max_visible_list_size = + two_to_16(trav->value); + } else if (trav->type == 0x0002) { + ((IMCOMM *) handle)->max_invisible_list_size = + two_to_16(trav->value); + } + } + + clear_tlv_list(tlvlist); + + return IMCOMM_RET_OK; +} + +/* PROTO */ +IMCOMM_RET +snac_set_location_info(void *handle) +{ + pkt_t *packet; + char *idstr = "text/aolrtf; charset=\"iso-8859-1\""; + int pktlen = 0; + uint8_t capabilities[] = + {0x09, 0x46, 0x13, 0x46, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, + 0x45, 0x53, 0x54, + 0x00, 0x00, + 0x09, 0x46, 0x13, 0x4d, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, + 0x45, 0x53, 0x54, 0x00, 0x00, + 0x09, 0x46, 0x00, 0x00, 0x4c, 0x7f, 0x11, 0xd1, 0x82, 0x22, 0x44, + 0x45, 0x53, 0x54, 0x00, 0x00 + }; + + snac_send_cli_update(handle); + + if (((IMCOMM *) handle)->profile_str != NULL) + pktlen += + 8 + strlen(idstr) + + strlen((char *) ((IMCOMM *) handle)->profile_str); + if (((IMCOMM *) handle)->away_msg != NULL) + pktlen += strlen((char *) ((IMCOMM *) handle)->away_msg); + + packet = + pkt_init(pktlen + 10 + 8 + 4 + strlen(idstr) + + sizeof(capabilities)); + + pkt_add16(packet, 0x0001); + pkt_add16(packet, (uint16_t) strlen(idstr)); + pkt_addraw(packet, (uint8_t *) idstr, strlen(idstr)); + + if (((IMCOMM *) handle)->profile_str != NULL) { + pkt_add16(packet, 0x0002); + pkt_add16(packet, + (uint16_t) strlen((char *) ((IMCOMM *) handle)-> + profile_str)); + pkt_addraw(packet, ((IMCOMM *) handle)->profile_str, + strlen((char *) ((IMCOMM *) handle)->profile_str)); + } + pkt_add16(packet, 0x0003); + pkt_add16(packet, (uint16_t) strlen(idstr)); + pkt_addraw(packet, (uint8_t *) idstr, strlen(idstr)); + pkt_add16(packet, 0x0004); + + if (((IMCOMM *) handle)->away_msg != NULL) { + pkt_add16(packet, + (uint16_t) strlen((char *) ((IMCOMM *) handle)-> + away_msg)); + pkt_addraw(packet, ((IMCOMM *) handle)->away_msg, + (uint16_t) strlen((char *) ((IMCOMM *) handle)-> + away_msg)); + } else { + pkt_add16(packet, 0x0000); + } + + pkt_add16(packet, 0x0005); + pkt_add16(packet, (uint16_t) sizeof(capabilities)); + pkt_addraw(packet, capabilities, sizeof(capabilities)); + pkt_add16(packet, 0x0006); + pkt_add16(packet, 0x0006); + pkt_add16(packet, 0x0004); + pkt_add32(packet, 0x00020002); + + snac_sendpkt(handle, 0x02, 0x04, packet, 0); + pkt_free(packet); + return IMCOMM_RET_OK; +} + +/* PROTO */ +IMCOMM_RET +snac_send_icbm_params(void *handle, uint16_t channel, uint16_t max_msg_size) +{ + IMCOMM_RET ret; + pkt_t *packet; + + packet = pkt_init(16); + pkt_add32(packet, 0x00000000); + pkt_add16(packet, 0x000b); + pkt_add16(packet, 0x1f40); + pkt_add16(packet, ((IMCOMM *) handle)->max_sender_warning); + pkt_add16(packet, ((IMCOMM *) handle)->max_receiver_warning); + pkt_add32(packet, 0x00000000); + + ret = snac_sendpkt(handle, 0x04, 0x02, packet, 0); + pkt_free(packet); + return ret; +} + +/* PROTO */ +IMCOMM_RET +snac_ssi_activate(void *handle) +{ + if (!((IMCOMM *) handle)->connected) { + ((IMCOMM *) handle)->connected = 1; + return multi_ssiact_cliready(handle); + } else { + return IMCOMM_RET_OK; + } +} + +/* PROTO */ +IMCOMM_RET +snac_ssi_get_list(void *handle, uint8_t * data, uint16_t len) +{ + uint8_t version, *name; + uint16_t x, count, length, group_id, id, type, tlvlen; + pkt_t *pkt; + + pkt = pkt_initP(data + 10, len - 10); + + version = pkt_get8(pkt); + count = pkt_get16(pkt); + + for (x = 0; x < count; x++) { + length = pkt_get16(pkt); + if (length > 0) { + name = pkt_getstr(pkt, length); + } else { + name = NULL; + } + + group_id = pkt_get16(pkt); + id = pkt_get16(pkt); + type = pkt_get16(pkt); + tlvlen = pkt_get16(pkt); + pkt_skip(pkt, tlvlen); + + if (type == 0x0000 && name != NULL) { + imcomm_addtobuddylist(handle, (char *) name, id, group_id); + } + free(name); + } + + pkt_freeP(pkt); + return IMCOMM_RET_OK; +} + + + +/* PROTO */ +IMCOMM_RET +snac_send_cli_update(void *handle) +{ + IMCOMM_RET ret; + pkt_t *pkt; + + /* + * This makes the server send us extended status information + */ +#if 0 + pkt = pkt_init(12); + pkt_add16(pkt, 0x001d); + pkt_add16(pkt, 0x0008); + pkt_add32(pkt, 0x00020404); + pkt_add32(pkt, 0x00000000); +#endif + + pkt = pkt_init(8); + pkt_add16(pkt, 0x0006); + pkt_add16(pkt, 0x0004); + if (((IMCOMM *) handle)->isinvisible) + pkt_add32(pkt, 0x00000100); + else + pkt_add32(pkt, 0x00000000); + + ret = snac_sendpkt(handle, 0x01, 0x1e, pkt, 0); + pkt_free(pkt); + return ret; +} + +/* PROTO */ +IMCOMM_RET +multi_ssiact_cliready(void *handle) +{ + struct MultiPacket *multipkt; + pkt_t *cliupdpkt; + unsigned char cli_ready_packet[] = {0x00, + 0x13, 0x00, 0x03, 0x01, 0x10, 0x08, 0xE5, 0x00, 0x0b, 0x00, 0x01, + 0x01, 0x10, 0x08, 0xe5, 0x00, 0x0a, 0x00, 0x01, 0x01, 0x10, + 0x08, 0xe5, 0x00, 0x09, 0x00, 0x01, 0x01, 0x10, 0x08, 0xe5, + 0x00, 0x08, 0x00, 0x01, 0x01, 0x04, 0x00, 0x01, 0x00, 0x06, + 0x00, 0x01, 0x01, 0x10, 0x08, 0xe5, 0x00, 0x04, 0x00, 0x01, + 0x01, 0x10, 0x08, 0xe5, 0x00, 0x03, 0x00, 0x01, 0x01, 0x10, + 0x08, 0xe5, 0x00, 0x02, 0x00, 0x01, 0x01, 0x10, 0x08, 0xe5, + 0x00, 0x01, 0x00, 0x04, 0x01, 0x10, 0x08, 0xe5 + }; + + multipkt = MultiPktInit(); + + cliupdpkt = pkt_init(12); + pkt_add16(cliupdpkt, 0x001d); + pkt_add16(cliupdpkt, 0x0008); + pkt_add32(cliupdpkt, 0x00020404); + pkt_add32(cliupdpkt, 0x00000000); + + snac_addToMulti(handle, multipkt, 0x01, 0x1e, cliupdpkt->data, + cliupdpkt->len, 0); + snac_addToMulti(handle, multipkt, 0x01, 0x02, cli_ready_packet, + sizeof(cli_ready_packet), 0); + snac_addToMulti(handle, multipkt, 0x13, 0x07, NULL, 0, 0); + + flap_sendMulti(handle, multipkt); + MultiPktFree(multipkt); + pkt_free(cliupdpkt); + + if (((IMCOMM *) handle)->callbacks[IMCOMM_ERROR]) + ((IMCOMM *) handle)->callbacks[IMCOMM_ERROR] (handle, + IMCOMM_STATUS_CONNECTED); + + return IMCOMM_RET_OK; +} + +/* PROTO */ +IMCOMM_RET +snac_send_cli_ready(void *handle) +{ + unsigned char packet[] = + {0x00, 0x01, 0x00, 0x04, 0x01, 0x10, 0x08, 0xf1, 0x00, 0x13, 0x00, + 0x03, + 0x01, 0x10, 0x08, 0xf1, + 0x00, 0x02, 0x00, 0x01, 0x01, 0x10, 0x08, 0xf1, 0x00, 0x03, 0x00, + 0x01, + 0x01, 0x10, 0x08, 0xf1, + 0x00, 0x08, 0x00, 0x01, 0x01, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x01, + 0x01, 0x10, 0x08, 0xf1, + 0x00, 0x06, 0x00, 0x01, 0x01, 0x10, 0x08, 0xf1, 0x00, 0x09, 0x00, + 0x01, + 0x01, 0x10, 0x08, 0xf1, + 0x00, 0x0A, 0x00, 0x01, 0x01, 0x10, 0x08, 0xf1, 0x00, 0x0B, 0x00, + 0x01, + 0x01, 0x10, 0x08, 0xf1 + }; + snac_send(handle, 0x01, 0x02, packet, sizeof(packet), 0); + if (((IMCOMM *) handle)->callbacks[IMCOMM_ERROR]) + ((IMCOMM *) handle)->callbacks[IMCOMM_ERROR] (handle, + IMCOMM_STATUS_CONNECTED); + + return IMCOMM_RET_OK; +} + +/* PROTO */ +size_t +count_tlv(unsigned char *data, size_t len) +{ + pkt_t *tp; + size_t num; + + tp = pkt_initP(data, len); + + num = count_tlv_pkt(tp); + pkt_freeP(tp); + + return num; +} + +/* PROTO */ +size_t +count_tlv_pkt(pkt_t * tp) +{ + size_t num = 0; + + while (tp->offset < tp->len) { + pkt_get16(tp); + pkt_skip(tp, pkt_get16(tp)); + num++; + } + + return num; +} + +/* PROTO */ +TLVLIST * +tlv_split(unsigned char *data, size_t len, size_t numtlv) +{ + TLVLIST *newtlv = 0, *tlvlist = 0, *firsttlv = 0; + uint16_t x = 0, counter = 0; + int firstTime = 1; + + while (x < len) { + newtlv = malloc(sizeof(TLVLIST)); + newtlv->type = two_to_16(data + x); + newtlv->len = two_to_16(data + x + 2); + + x += 4; + if (newtlv->len != 0) { + newtlv->value = malloc(newtlv->len); + memcpy(newtlv->value, data + x, newtlv->len); + } + newtlv->next = NULL; + if (firstTime) { + tlvlist = newtlv; + firsttlv = newtlv; + firstTime = 0; + } else { + tlvlist->next = newtlv; + tlvlist = tlvlist->next; + } + + if (newtlv->len != 0) { + x += newtlv->len; + counter++; + } + } + +#ifdef DEBUG + for (tlvlist = firsttlv; tlvlist != NULL; tlvlist = tlvlist->next) + printf("TLV type: %04X length: %04X\n", tlvlist->type, + tlvlist->len); +#endif + + return firsttlv; +} + +/* PROTO */ +void +clear_tlv_list(TLVLIST * tlvlist) +{ + TLVLIST *temp, *trav = tlvlist; + + while (trav != NULL) { + temp = trav; + trav = trav->next; + if (temp->len > 0) + free(temp->value); + free(temp); + } +} + +/* PROTO */ +uint32_t +four_to_32(unsigned char *value) +{ + uint32_t temp; + + memcpy(&temp, value, 4); + + if (endianness == HOST_LITTLE_ENDIAN) + temp = BYTE_SWAP_32(temp); + + return temp; +} + +/* PROTO */ +uint16_t +two_to_16(unsigned char *value) +{ + uint16_t temp; + + memcpy(&temp, value, 2); + + if (endianness == HOST_LITTLE_ENDIAN) + temp = BYTE_SWAP_16(temp); + + return temp; +} + +/* PROTO */ +IMCOMM_RET +snac_get_incoming_im(void *handle, uint8_t * data, uint16_t len) +{ + char *sn; + uint8_t sn_len = data[20]; + char *msg; + TLVLIST *tlvlist, *trav, *trav2, *subtlv; + int auto_resp = 0; + int numtlv; + + + numtlv = two_to_16(data + sn_len + 23); + sn = malloc(sn_len + 1); + memcpy(sn, data + 21, sn_len); + sn[sn_len] = 0; + + tlvlist = tlv_split(data + 25 + sn_len, len - 25 - sn_len, numtlv + 1); + for (trav = tlvlist; trav != NULL; trav = trav->next) { + if (trav->type == 0x0004 && trav->len == 0) + auto_resp = 1; + + if (trav->type == 0x0003) { + imcomm_update_buddy_times(handle, sn, 2, + four_to_32(trav->value)); + } + } + + if (!auto_resp) + imcomm_update_buddy_times(handle, sn, 1, 0); + + for (trav = tlvlist; trav != NULL; trav = trav->next) + if (trav->type == 0x0002) + break; + + if (trav == NULL) { + clear_tlv_list(tlvlist); + free(sn); + return IMCOMM_RET_ERROR; + } + subtlv = tlv_split(trav->value, trav->len, 2); + for (trav2 = subtlv; trav2 != NULL; trav2 = trav2->next) + if (trav2->type == 0x0101) + break; + + if (trav2 == NULL) { + clear_tlv_list(subtlv); + clear_tlv_list(tlvlist); + free(sn); + return IMCOMM_RET_ERROR; + } + msg = malloc(trav2->len - 3); + memcpy(msg, trav2->value + 4, trav2->len - 4); + msg[trav2->len - 4] = 0; + + if (((IMCOMM *) handle)->callbacks[IMCOMM_IM_INCOMING]) + (((IMCOMM *) handle)->callbacks[IMCOMM_IM_INCOMING]) (handle, sn, + auto_resp, + msg); + + free(msg); + clear_tlv_list(subtlv); + clear_tlv_list(tlvlist); + free(sn); + return IMCOMM_RET_OK; +} + +/* PROTO */ +IMCOMM_RET +snac_get_signoff(void *handle, uint8_t * data, uint16_t len) +{ + char *sn; + int sn_len = (int) data[10]; + + sn = malloc(sn_len + 1); + memcpy(sn, data + 11, sn_len); + sn[sn_len] = 0; + imcomm_internal_delete_buddy(handle, sn); + + if (((IMCOMM *) handle)->callbacks[IMCOMM_IM_SIGNOFF]) + ((IMCOMM *) handle)->callbacks[IMCOMM_IM_SIGNOFF] (handle, sn); + + free(sn); + return IMCOMM_RET_OK; +} + +/* PROTO */ +IMCOMM_RET +snac_get_signon(void *handle, uint8_t * data, uint16_t len) +{ + char *sn; + int sn_len = (int) data[10]; + int numtlv = two_to_16(data + 13 + sn_len); + unsigned long idletime = 0; + unsigned long onlinetime = 0; + int isaway = 0; + TLVLIST *temp, *tlvlist; + + sn = malloc(sn_len + 1); + memcpy(sn, data + 11, sn_len); + sn[sn_len] = 0; + tlvlist = + tlv_split(data + 11 + sn_len + 4, len - 11 - sn_len - 4, numtlv); + + for (temp = tlvlist; temp != NULL; temp = temp->next) { + if (temp->type == 0x0004) { + idletime = two_to_16(temp->value); + } + if (temp->type == 0x0001) { + if (temp->value[1] == 0x30 || temp->value[1] == 0x31 + || temp->value[1] == 0x24) + isaway = 1; + } + if (temp->type == 0x0003) { + onlinetime = four_to_32(temp->value); + imcomm_update_buddy_times(handle, sn, 2, onlinetime); + } + } + if (imcomm_internal_add_buddy(handle, sn, idletime, onlinetime, isaway) + == 0) { + imcomm_update_buddy_times(handle, sn, 1, idletime); + imcomm_update_buddy_away(handle, sn, isaway); + } else { + if (((IMCOMM *) handle)->callbacks[IMCOMM_IM_SIGNON]) + ((IMCOMM *) handle)->callbacks[IMCOMM_IM_SIGNON] (handle, sn); + if (((IMCOMM *) handle)->callbacks[IMCOMM_IM_IDLEINFO]) + ((IMCOMM *) handle)->callbacks[IMCOMM_IM_IDLEINFO] (handle, sn, + idletime); + if (isaway) + if (((IMCOMM *) handle)->callbacks[IMCOMM_IM_BUDDYAWAY]) + ((IMCOMM *) handle)-> + callbacks[IMCOMM_IM_BUDDYAWAY] (handle, sn); + } + clear_tlv_list(tlvlist); + + free(sn); + return IMCOMM_RET_OK; +} + + +/* PROTO */ +void +snac_get_user_info(void *handle, uint8_t * data, uint16_t len) +{ + int sn_len = (int) data[0]; + char *sn; + char *profilestr = NULL; + char *awaymsg = NULL; + TLVLIST *tlvlist, *trav; + + sn = malloc(sn_len + 1); + memcpy(sn, data + 1, sn_len); + sn[sn_len] = 0; + + tlvlist = + tlv_split(data + 5 + sn_len, len - 5 - sn_len, + data[sn_len + 4] + 2); + + if (tlvlist == NULL) { + free(sn); + return; + } + if (tlvlist->next == NULL) { + free(sn); + clear_tlv_list(tlvlist); + return; + } + for (trav = tlvlist->next->next; trav != NULL; trav = trav->next) { + switch (trav->type) { + case 0x02: + profilestr = malloc(trav->len + 1); + strncpy(profilestr, (char *) trav->value, trav->len); + profilestr[trav->len] = 0; + break; + case 0x04: + if (trav->len == 2) /* idle time? */ + break; + + awaymsg = malloc(trav->len + 1); + strncpy(awaymsg, (char *) trav->value, trav->len); + awaymsg[trav->len] = 0; + break; + } + } + + if (profilestr != NULL) { + if (((IMCOMM *) handle)->callbacks[IMCOMM_IM_PROFILE]) { + ((IMCOMM *) handle)->callbacks[IMCOMM_IM_PROFILE] (handle, sn, + profilestr); + free(profilestr); + } + } else if (awaymsg != NULL) { + if (((IMCOMM *) handle)->callbacks[IMCOMM_IM_AWAYMSG]) { + ((IMCOMM *) handle)->callbacks[IMCOMM_IM_AWAYMSG] (handle, sn, + awaymsg); + free(awaymsg); + } + } + free(sn); + clear_tlv_list(tlvlist); +} + +/* PROTO */ +void +imcomm_im_send_message(void *handle, const char *whom, const char *msg, int automsg) +{ + pkt_t *packet; + + packet = pkt_init(28 + strlen(whom) + strlen(msg) + (4 * automsg)); + + /* + * Message cookie? + * + * Putting something random seems to work. + */ + pkt_add32(packet, 0x01020304); + pkt_add32(packet, 0x05060708); + + pkt_add16(packet, 0x0001); + pkt_add8(packet, (uint8_t) strlen(whom)); + pkt_addraw(packet, (uint8_t *) whom, strlen(whom)); + pkt_add16(packet, 0x0002); + pkt_add16(packet, (uint16_t) (uint16_t) (strlen(msg) + 13)); + pkt_add32(packet, 0x05010001); + pkt_add8(packet, 0x01); + pkt_add16(packet, 0x0101); + pkt_add16(packet, (uint16_t) (uint16_t) (strlen(msg) + 4)); + pkt_add32(packet, 0x00000000); + pkt_addraw(packet, (uint8_t *) msg, strlen(msg)); + + if (automsg) { + pkt_add16(packet, 0x0004); + pkt_add16(packet, 0x0000); + } + snac_sendpkt(handle, 0x04, 0x06, packet, (automsg ? 0 : 1)); + pkt_free(packet); +} + +/* PROTO */ +void +imcomm_request_awayprofile(void *handle, char *sn) +{ + pkt_t *packet; + struct MultiPacket *mpkt; + + mpkt = MultiPktInit(); + + packet = pkt_init(3 + (uint8_t) strlen(sn)); + + pkt_add16(packet, 0x0003); + pkt_add8(packet, (uint8_t) strlen(sn)); + pkt_addraw(packet, (uint8_t *) sn, strlen(sn)); + + snac_addToMulti(handle, mpkt, 0x02, 0x05, packet->data, packet->len, + 0); + + pkt_free(packet); + + packet = pkt_init(3 + (uint8_t) strlen(sn)); + + pkt_add16(packet, 0x0001); + pkt_add8(packet, (uint8_t) strlen(sn)); + pkt_addraw(packet, (uint8_t *) sn, strlen(sn)); + + snac_addToMulti(handle, mpkt, 0x02, 0x05, packet->data, packet->len, + 0); + pkt_free(packet); + + flap_sendMulti(handle, mpkt); + MultiPktFree(mpkt); +} + +/* PROTO */ +void +imcomm_request_profile(void *handle, char *sn) +{ + pkt_t *packet; + + packet = pkt_init(3 + (uint8_t) strlen(sn)); + + pkt_add16(packet, 0x0001); + pkt_add8(packet, (uint8_t) strlen(sn)); + pkt_addraw(packet, (uint8_t *) sn, strlen(sn)); + + snac_sendpkt(handle, 0x02, 0x05, packet, 0); + pkt_free(packet); +} + +/* PROTO */ +void +imcomm_request_awaymsg(void *handle, char *sn) +{ + pkt_t *packet; + + packet = pkt_init(3 + (uint8_t) strlen(sn)); + + pkt_add16(packet, 0x0003); + pkt_add8(packet, (uint8_t) strlen(sn)); + pkt_addraw(packet, (uint8_t *) sn, strlen(sn)); + + snac_sendpkt(handle, 0x02, 0x05, packet, 0); + pkt_free(packet); +} + +/* PROTO */ +void +imcomm_request_massawaymsg(void *handle, char **sns, int num) +{ + pkt_t *packet; + int x; + struct MultiPacket *multipkt; + + multipkt = MultiPktInit(); + + for (x = 0; x < num; x++) { + packet = pkt_init(3 + (uint8_t) strlen(sns[x])); + + pkt_add16(packet, 0x0003); + pkt_add8(packet, (uint8_t) strlen(sns[x])); + pkt_addraw(packet, (uint8_t *) sns[x], strlen(sns[x])); + + snac_addToMulti(handle, multipkt, 0x02, 0x05, packet->data, + (uint16_t) packet->len, 0); + pkt_free(packet); + } + + flap_sendMulti(handle, multipkt); + MultiPktFree(multipkt); +} + +/* PROTO */ +void +imcomm_addtobuddylist(void *handle, char *sn, uint16_t id, uint16_t group_id) +{ + IMCOMM_BUDDYLIST *temp, *trav; + char *sname; + + sname = imcomm_simplify_sn(sn); + + for (trav = ((IMCOMM *) handle)->buddylist; trav != NULL; + trav = trav->next) { + if (strcmp(sname, trav->sn) == 0) { + free(sname); + return; + } + } + + temp = malloc(sizeof(IMCOMM_BUDDYLIST)); + temp->sn = sname; + temp->formattedsn = strdup(sn); + temp->ssi_id = id; + temp->group_id = group_id; + temp->next = NULL; + + if (((IMCOMM *) handle)->buddylist == NULL) + ((IMCOMM *) handle)->buddylist = temp; + else { + for (trav = ((IMCOMM *) handle)->buddylist; trav->next != NULL; + trav = trav->next); + + trav->next = temp; + } +} + +/* PROTO */ +uint16_t +imcomm_get_next_id(void *handle) +{ + IMCOMM_BUDDYLIST *trav; + uint16_t firstid = 0x0001; + uint8_t found; + + /* this is supremely gross */ + + while (1) { + found = 0; + + for (trav = ((IMCOMM *) handle)->buddylist; trav != NULL; + trav = trav->next) { + if (trav->ssi_id == firstid) { + found = 1; + break; + } + } + + if (found == 1) { + firstid++; + } else { + break; + } + } + + return firstid; +} + +/* PROTO */ +void +imcomm_im_add_buddy(void *handle, char *sn) +{ + IMCOMM_BUDDYLIST *temp, *trav; + struct MultiPacket *mpkt; + pkt_t *packet; + char *sname; + uint16_t nextid; + + sname = imcomm_simplify_sn(sn); + + for (trav = ((IMCOMM *) handle)->buddylist; trav != NULL; + trav = trav->next) { + if (strcmp(sname, trav->sn) == 0) { + free(sname); + return; + } + } + + nextid = imcomm_get_next_id(handle); + + temp = malloc(sizeof(IMCOMM_BUDDYLIST)); + temp->sn = sname; + temp->formattedsn = strdup(sname); + temp->ssi_id = nextid; + temp->next = NULL; + + if (((IMCOMM *) handle)->buddylist == NULL) + ((IMCOMM *) handle)->buddylist = temp; + else { + for (trav = ((IMCOMM *) handle)->buddylist; trav->next != NULL; + trav = trav->next); + + trav->next = temp; + } + + mpkt = MultiPktInit(); + + snac_addToMulti(handle, mpkt, 0x13, 0x11, NULL, 0, 0); + packet = pkt_init(10 + strlen(sname)); + pkt_add16(packet, (uint16_t) strlen(sname)); + pkt_addraw(packet, (unsigned char *) sname, strlen(sname)); + pkt_add16(packet, 0x0001); + pkt_add16(packet, nextid); + pkt_add16(packet, 0x0000); + pkt_add16(packet, 0x0000); + snac_addToMulti(handle, mpkt, 0x13, 0x08, packet->data, packet->len, + 0); + pkt_free(packet); + + snac_addToMulti(handle, mpkt, 0x13, 0x012, NULL, 0, 0); + + flap_sendMulti(handle, mpkt); + MultiPktFree(mpkt); +} + +/* PROTO */ +void +imcomm_im_remove_buddy(void *handle, const char *sn) +{ + char *sname, *snsend = NULL; + pkt_t *packet; + IMCOMM_BUDDYLIST *temp, *trav; + struct MultiPacket *mpkt; + uint16_t buddy_id = 0x00, buddy_group_id = 0x00; + + sname = imcomm_simplify_sn(sn); + + if (((IMCOMM *) handle)->buddylist != NULL) { + if (strcmp(((IMCOMM *) handle)->buddylist->sn, sname) == 0) { + temp = ((IMCOMM *) handle)->buddylist; + ((IMCOMM *) handle)->buddylist = + ((IMCOMM *) handle)->buddylist->next; + + buddy_id = temp->ssi_id; + buddy_group_id = temp->group_id; + snsend = temp->formattedsn; + free(temp->sn); + free(temp); + } else { + for (trav = ((IMCOMM *) handle)->buddylist; trav->next != NULL; + trav = trav->next) { + if (strcmp(trav->next->sn, sname) == 0) { + temp = trav->next; + trav->next = trav->next->next; + + buddy_id = temp->ssi_id; + buddy_group_id = temp->group_id; + snsend = temp->formattedsn; + free(temp->sn); + free(temp); + break; + } + } + } + } + imcomm_internal_delete_buddy(handle, sn); + + if (snsend == NULL) { + free(sname); + return; + } + /* + * packet = malloc(strlen(sname) + 1); packet[0] = strlen(sname); + * memcpy(packet + 1, sname, strlen(sname)); + * + * snac_send(handle, 0x03, 0x05, packet, (uint16_t) (strlen(sname) + 1), + * 0); free(packet); + */ + + mpkt = MultiPktInit(); + + snac_addToMulti(handle, mpkt, 0x13, 0x11, NULL, 0, 0); + packet = pkt_init(10 + strlen(snsend)); + pkt_add16(packet, (uint16_t) strlen(snsend)); + pkt_addraw(packet, (unsigned char *) snsend, strlen(snsend)); + pkt_add16(packet, buddy_group_id); + pkt_add16(packet, buddy_id); + pkt_add16(packet, 0x0000); + pkt_add16(packet, 0x0000); + snac_addToMulti(handle, mpkt, 0x13, 0x0a, packet->data, packet->len, + 0); + pkt_free(packet); + + snac_addToMulti(handle, mpkt, 0x13, 0x012, NULL, 0, 0); + + flap_sendMulti(handle, mpkt); + MultiPktFree(mpkt); + free(sname); + free(snsend); +} + +/* PROTO */ +void +snac_request_new_service(void *handle, uint16_t service) +{ + pkt_t *pkt; + + pkt = pkt_init(2); + pkt_add16(pkt, service); + snac_sendpkt(handle, 0x01, 0x04, pkt, 0); + pkt_free(pkt); +} + +/* PROTO */ +void +snac_new_subconnection(void *handle, unsigned char *data, uint16_t len) +{ + TLVLIST *tv, *trav; + uint16_t subtype = 0, cookie_len = 0; + void *h; + unsigned char *cookie = 0, *server = 0, *serverport; + + tv = tlv_split(data, len, 3); + + for (trav = tv; trav != NULL; trav = trav->next) { + if (trav->type == 0x000D) { + subtype = two_to_16(trav->value); + } else if (trav->type == 0x0005) { + server = malloc((trav->len) + 1); + memcpy(server, trav->value, trav->len); + server[trav->len] = 0; + } else if (trav->type == 0x0006) { + cookie = malloc(trav->len); + memcpy(cookie, trav->value, trav->len); + cookie_len = trav->len; + } + } + + clear_tlv_list(tv); + + if (strchr((char *) server, ':') == NULL) { + serverport = malloc(strlen((char *) server) + 7); + snprintf((char *) serverport, strlen((char *) server) + 7, "%s:%d", + (char *) server, ((IMCOMM *) handle)->oscarport); + free(server); + server = serverport; + } +#ifdef DEBUG + printf + ("New connection info: Type %02X, server %s. Cookie len %d bytes.\n", + subtype, server, cookie_len); +#endif + + h = imcomm_create_child_handle(handle); + bos_signon_phase2(h, server, cookie, cookie_len); + + free(server); + free(cookie); + + return; +} + +/* PROTO */ +void +imcomm_upload_icon(void *handle, uint8_t * data, uint16_t icon_len) +{ + /* this is really badly broken */ + /* I'm disabling it for now */ + + /* + * snac_request_new_service(handle, 0x10); ((IMCOMM *) + * handle)->icondata = malloc(icon_len); memcpy(((IMCOMM *) + * handle)->icondata, data, icon_len); ((IMCOMM *) handle)->iconlen = + * icon_len; + */ +} + +/* PROTO */ +void +snac_finish_buddy_icon(void *handle) +{ + /* + * The icon data is contained in the parent's node + */ + + pkt_t *newpkt; + void *pptr = ((IMCOMM *) handle)->parent; + + newpkt = pkt_init(4 + ((IMCOMM *) pptr)->iconlen); + pkt_add16(newpkt, 0x0001); + pkt_add16(newpkt, ((IMCOMM *) pptr)->iconlen); + pkt_addraw(newpkt, ((IMCOMM *) pptr)->icondata, + ((IMCOMM *) pptr)->iconlen); + + snac_sendpkt(handle, 0x10, 0x02, newpkt, 0); + pkt_free(newpkt); +} diff --git a/libs/libimcomm/test.c b/libs/libimcomm/test.c new file mode 100644 index 0000000..f65bcc5 --- /dev/null +++ b/libs/libimcomm/test.c @@ -0,0 +1,186 @@ +/** _ + ** (_)_ __ __ ___ _ __ _ __ + ** | | ' \/ _/ _ \ ' \| ' \ + ** |_|_|_|_\__\___/_|_|_|_|_|_| + ** + ** Copyright (C) 2003-2005, Claudio Leite + ** All rights reserved. + ** + ** Please see the file 'COPYING' for licensing information. + **/ + +#include "imcomm.h" + +void buddy_online(void *h, const char *who); +void buddy_offline(void *h, const char *who); +void idleinfo(void *, const char *, unsigned long); +void error(void *h, int errornum); +void incoming_im(void *, const char *, const int, const char *); +char *strip_html(char *message); + +void +incoming_im(void *handle, const char *who, const int automessage, + const char *message) +{ + char *msg; + msg = strip_html((char *) message); + printf("[%s] %s\n", who, msg); + + if (strcmp(msg, "quit now") == 0) { +#ifdef MACINTOSH_CLASSIC + mactcp_close(handle); + CloseResolver(); +#endif + free(msg); + exit(0); + } + free(msg); +} + +int +main(int argc, char *argv[]) +{ + void *handle; + +#ifndef MACINTOSH_CLASSIC + fd_set readfs; + struct timeval tm; + + tm.tv_sec = 2; + tm.tv_usec = 150000; +#endif + + handle = imcomm_create_handle(); + imcomm_register_callback(handle, IMCOMM_IM_SIGNON, buddy_online); + imcomm_register_callback(handle, IMCOMM_IM_SIGNOFF, buddy_offline); + imcomm_register_callback(handle, IMCOMM_IM_IDLEINFO, idleinfo); + imcomm_register_callback(handle, IMCOMM_ERROR, error); + imcomm_register_callback(handle, IMCOMM_IM_INCOMING, incoming_im); + imcomm_im_signon(handle, argv[1], argv[2]); + printf("Starting IMComm test program...\n"); + + while (1) { +#ifdef MACINTOSH_CLASSIC + imcomm_select(NULL, NULL, NULL, NULL, NULL); +#else + FD_ZERO(&readfs); +#if 0 + FD_SET(fileno(stdin), &readfs); +#endif + imcomm_select(0, &readfs, NULL, NULL, &tm); + fflush(stdout); +#endif + } + + return 0; +} + +void +buddy_online(void *h, const char *who) +{ + printf(">>> %s is now online\n", who); + return; +} + +void +buddy_offline(void *h, const char *who) +{ + printf("<<< %s is now offline\n", who); + return; +} + +void +idleinfo(void *h, const char *who, unsigned long time) +{ + printf("*** Idle: %s, %ld\n", who, time); + return; +} + +void +error(void *h, int errornum) +{ + printf("*** "); + + switch (errornum) { + case IMCOMM_STATUS_CONNECTED: + printf("Connected.\n"); + break; + case IMCOMM_ERROR_INVALID_LOGIN: + printf("Login failed.\n"); + break; + case IMCOMM_ERROR_DISCONNECTED: + printf("Disconnected.\n"); + break; + case IMCOMM_ERROR_OTHER_SIGNON: + printf + ("You've been disconnected because you signed on at a different location.\n"); + break; + case IMCOMM_STATUS_AUTHDONE: + printf("Authentication succeeded.\n"); + break; + default: + printf("Unknown error type.\n"); + break; + } +} + +char * +strip_html(char *message) +{ + char *temp; + int x, count, inhtml; + + temp = malloc(strlen(message) + 1); + for (x = 0, count = 0, inhtml = 0; x < strlen(message); x++) { + if (message[x] == '&') { + if (x + 4 < strlen(message)) { + if (strncmp(message + x, "&", 5) == 0) { + temp[count] = '&'; + count++; + x += 4; + continue; + } + } + if (x + 5 < strlen(message)) { + if (strncmp(message + x, """, 6) == 0) { + temp[count] = '\"'; + count++; + x += 5; + continue; + } + } + if (x + 3 < strlen(message)) { + if (strncmp(message + x, "<", 4) == 0) { + temp[count] = '<'; + count++; + x += 3; + continue; + } + } + if (x + 3 < strlen(message)) { + if (strncmp(message + x, ">", 4) == 0) { + temp[count] = '>'; + count++; + x += 3; + continue; + } + } + } + if (message[x] == '<') + inhtml = 1; + if (inhtml) { + if (message[x] == '>') + inhtml = 0; + continue; + } + if (message[x] == '\n' || message[x] == '\r') + temp[count] = ' '; + else + temp[count] = message[x]; + count++; + } + + temp = realloc(temp, count + 1); + temp[count] = 0; + return temp; +} diff --git a/libs/libjabber/Jamfile b/libs/libjabber/Jamfile index 483de14..b1901bd 100644 --- a/libs/libjabber/Jamfile +++ b/libs/libjabber/Jamfile @@ -30,5 +30,3 @@ if $(HAVE_OPENSSL) { } StaticLibrary libjabber.a : $(sources) ; - - diff --git a/protocols/Jamfile b/protocols/Jamfile index b6f56b5..07fb167 100644 --- a/protocols/Jamfile +++ b/protocols/Jamfile @@ -2,3 +2,4 @@ SubDir TOP protocols ; # Include all the components. SubInclude TOP protocols gtalk ; +SubInclude TOP protocols aim ; diff --git a/protocols/aim/AIM.cpp b/protocols/aim/AIM.cpp new file mode 100644 index 0000000..1dacd5e --- /dev/null +++ b/protocols/aim/AIM.cpp @@ -0,0 +1,496 @@ +#include +#include +#include + +#include + +#include "AIM.h" + +const char* kProtocolName = "aim"; + +CayaProtocolMessengerInterface *gServerMsgr; + + +AIMProtocol::AIMProtocol() +{ + +} + + +AIMProtocol::~AIMProtocol() +{ + Shutdown(); +} + + +status_t +AIMProtocol::Init(CayaProtocolMessengerInterface* msgr) +{ + printf("init\n"); + gServerMsgr = msgr; + fIMCommHandle = imcomm_create_handle(); + fOnline = false; + + imcomm_register_callback(fIMCommHandle, IMCOMM_IM_INCOMING, (void (*)())GotMessage); + imcomm_register_callback(fIMCommHandle, IMCOMM_IM_SIGNON, (void (*)())BuddyOnline); + imcomm_register_callback(fIMCommHandle, IMCOMM_IM_SIGNOFF, (void (*)())BuddyOffline); + imcomm_register_callback(fIMCommHandle, IMCOMM_IM_BUDDYAWAY, (void (*)())BuddyAway); + imcomm_register_callback(fIMCommHandle, IMCOMM_IM_BUDDYUNAWAY, (void (*)())BuddyBack); + imcomm_register_callback(fIMCommHandle, IMCOMM_IM_AWAYMSG, (void (*)())BuddyAwayMsg); + imcomm_register_callback(fIMCommHandle, IMCOMM_IM_IDLEINFO, (void (*)())BuddyIdle); + imcomm_register_callback(fIMCommHandle, IMCOMM_IM_PROFILE, (void (*)())BuddyProfile); + + // XXX missing IMCOMM_ERROR, IMCOMM_FORMATTED_SN, IMCOMM_HANDLE_DELETED + + return B_OK; +} + + +status_t +AIMProtocol::Shutdown() +{ + LogOff(); + return B_OK; +} + + +status_t +AIMProtocol::Process(BMessage* msg) +{ + msg->PrintToStream(); + + switch (msg->what) { + case IM_MESSAGE: + { + int32 im_what = 0; + + msg->FindInt32("im_what", &im_what); + + switch (im_what) { + case IM_SET_STATUS: + { + int32 status = msg->FindInt32("status"); + BString status_msg(""); + msg->FindString("message", &status_msg); + char *smsg = strdup(status_msg.String()); + + switch (status) { + case CAYA_ONLINE: + { + if (!fOnline) { + A_LogOn(); + } else { + imcomm_set_unaway(fIMCommHandle); + } + break; + } + case CAYA_AWAY: + imcomm_set_away(fIMCommHandle, + smsg); + + break; + case CAYA_EXTENDED_AWAY: + imcomm_set_away(fIMCommHandle, + smsg); + + // UnsupportedOperation(); ? + break; + case CAYA_DO_NOT_DISTURB: + imcomm_set_away(fIMCommHandle, + smsg); + // UnsupportedOperation(); ? + break; + case CAYA_OFFLINE: + LogOff(); + break; + default: + break; + } + + free(smsg); + + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", IM_STATUS_SET); + msg.AddString("protocol", kProtocolName); + msg.AddInt32("status", status); + + gServerMsgr->SendMessage(&msg); + + break; + } + case IM_SET_NICKNAME: + { + UnsupportedOperation(); + break; + } + case IM_SEND_MESSAGE: + { + const char* buddy = msg->FindString("id"); + const char* sms = msg->FindString("message"); + imcomm_im_send_message(fIMCommHandle, buddy, + sms, 0); + + // XXX send a message to let caya know + // we did it + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", IM_MESSAGE_SENT); + msg.AddString("protocol", kProtocolName); + msg.AddString("id", buddy); + msg.AddString("message", sms); + + gServerMsgr->SendMessage(&msg); + break; + } + case IM_REGISTER_CONTACTS: + { + const char* buddy = NULL; + char *buddy_copy; + + for (int i = 0; + msg->FindString("id", i, &buddy) == B_OK; + i++) { + buddy_copy = strdup(buddy); + imcomm_im_add_buddy(fIMCommHandle, buddy_copy); + free(buddy_copy); + + } + break; + } + case IM_UNREGISTER_CONTACTS: + { + const char* buddy = NULL; + + for (int i = 0; + msg->FindString("id", i, &buddy) == B_OK; + i++) { + imcomm_im_remove_buddy(fIMCommHandle, buddy); + + } + + break; + } + case IM_USER_STARTED_TYPING: + { + // UnsupportedOperation(); + break; + } + case IM_USER_STOPPED_TYPING: + { + // UnsupportedOperation(); + break; + } + case IM_GET_CONTACT_INFO: + UnsupportedOperation(); + break; + case IM_SEND_AUTH_ACK: + { + UnsupportedOperation(); + break; + } + case IM_SPECIAL_TO_PROTOCOL: + UnsupportedOperation(); + break; + default: + msg->PrintToStream(); + return B_ERROR; + } + break; + } + default: + // We don't handle this what code + return B_ERROR; + } + + return B_OK; +} + + +void +AIMProtocol::UnsupportedOperation() { + printf("noop\n"); +} + +const char* +AIMProtocol::GetSignature() +{ + return kProtocolName; +} + + +const char* +AIMProtocol::GetFriendlySignature() +{ + return "AOL Instant Messenger"; +} + + +status_t +AIMProtocol::UpdateSettings(BMessage& msg) +{ + const char* username = NULL; + const char* password = NULL; + + msg.FindString("username", &username); + msg.FindString("password", &password); + // msg.FindString("server", &server); + // msg.FindInt32("port", &server); + + if ((username == NULL) || (password == NULL)) { + //LOG( kProtocolName, liHigh, "Invalid settings!"); + printf("Invalid settings"); + return B_ERROR; + } + + if ((fUsername != username) || (fPassword != password)) { + fUsername = username; + fPassword = password; + // XXX kill the handle and sign back in? + } + return B_OK; +} + + +uint32 +AIMProtocol::GetEncoding() +{ + return 0xffff; // No conversion, AIMProtocol handles UTF-8 ??? +} + + +status_t +AIMProtocol::A_LogOn() +{ + int ret = imcomm_im_signon(fIMCommHandle, fUsername, fPassword); + + printf("ret: %d\n", ret); + + if (ret == IMCOMM_RET_OK) { + fIMCommThread = spawn_thread(WaitForData, "imcomm receiver", + B_LOW_PRIORITY, this); + resume_thread(fIMCommThread); + + fOnline = true; + + return B_OK; + } + return B_ERROR; +} + + +status_t +AIMProtocol::LogOff() +{ + fOnline = false; + imcomm_delete_handle_now(fIMCommHandle); + + return B_OK; +} + +int32 +AIMProtocol::WaitForData(void *aimProtocol) { + // XXX No need for aimProtocol since imcomm does its own callback thing + printf("wait\n"); + fd_set readset; + struct timeval tm; + + while (1) { + FD_ZERO(&readset); + tm.tv_sec = 2; + tm.tv_usec = 500000; + + IMCOMM_RET ret = imcomm_select(1, &readset, NULL, NULL, &tm); + if (ret != IMCOMM_RET_OK && errno == EINTR) continue; + } + + return 0; +} + + +void +AIMProtocol::GotMessage(void *imcomm, char *who, int auto, char *recvmsg) { + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", IM_MESSAGE_RECEIVED); + msg.AddString("protocol", kProtocolName); + msg.AddString("id", who); + msg.AddString("message", strip_html(recvmsg)); + + gServerMsgr->SendMessage(&msg); +} + +void +AIMProtocol::BuddyOnline(void *imcomm, char *who) { + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", IM_STATUS_CHANGED); + msg.AddString("protocol", kProtocolName); + msg.AddString("id", who); + msg.AddInt32("status", CAYA_ONLINE); + + gServerMsgr->SendMessage(&msg); +} + +void +AIMProtocol::BuddyOffline(void *imcomm, char *who) { + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", IM_STATUS_CHANGED); + + msg.AddString("protocol", kProtocolName); + msg.AddString("id", who); + msg.AddInt32("status", CAYA_OFFLINE); + + gServerMsgr->SendMessage(&msg); +} + +void +AIMProtocol::BuddyAway(void *imcomm, char *who) { + imcomm_request_awaymsg(imcomm, who); +} + +void +AIMProtocol::BuddyBack(void *imcomm, char *who) { + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", IM_STATUS_CHANGED); + msg.AddString("protocol", kProtocolName); + msg.AddString("id", who); + msg.AddInt32("status", CAYA_ONLINE); + + gServerMsgr->SendMessage(&msg); +} + +void +AIMProtocol::BuddyAwayMsg(void *imcomm, char *who, char *awaymsg) { + BMessage msg(IM_MESSAGE); + + msg.AddInt32("im_what", IM_STATUS_CHANGED); + msg.AddString("protocol", kProtocolName); + msg.AddString("id", who); + msg.AddInt32("status", CAYA_EXTENDED_AWAY); + msg.AddString("message", strip_html(awaymsg)); + + gServerMsgr->SendMessage(&msg); +} + +void +AIMProtocol::BuddyIdle(void *imcomm, char *who, long idletime) { + BMessage msg(IM_MESSAGE); + msg.AddInt32("im_what", IM_STATUS_CHANGED); + msg.AddString("protocol", kProtocolName); + msg.AddString("id", who); + msg.AddInt32("status", CAYA_ONLINE); + + gServerMsgr->SendMessage(&msg); + +} + +void +AIMProtocol::BuddyProfile(void *handle, char *who, char *profile) { + // XXX vcard is probably an issue +} + +char * +AIMProtocol::strip_html(const char *message) +{ + char *temp; + int x, xnot, y, count, inhtml; + size_t len = strlen(message); + + temp = (char*)malloc(len + 1); + for (x = 0, count = 0, inhtml = 0; x < len; x++) { + if (message[x] == '<' && inhtml == 0) { + if (x + 10 < len) { + + /** + ** Convert links into + ** [http://url] link text + **/ + + if (strncasecmp(message + x, "", 4) == 0) { + temp[count] = '\n'; + count++; + x += 3; + continue; + } + } + inhtml = 1; + continue; + } + if (inhtml) { + if (message[x] == '>') + inhtml = 0; + + continue; + } + if (message[x] == '&') { + if (x + 4 < len) { + if (strncmp(message + x, "&", 5) == 0) { + temp[count] = '&'; + count++; + x += 4; + continue; + } + } + if (x + 5 < len) { + if (strncmp(message + x, """, 6) == 0) { + temp[count] = '\"'; + count++; + x += 5; + continue; + } + if (strncmp(message + x, " ", 6) == 0) { + temp[count] = ' '; + count++; + x += 5; + continue; + } + } + if (x + 3 < len) { + if (strncmp(message + x, "<", 4) == 0) { + temp[count] = '<'; + count++; + x += 3; + continue; + } + } + if (x + 3 < len) { + if (strncmp(message + x, ">", 4) == 0) { + temp[count] = '>'; + count++; + x += 3; + continue; + } + } + } + if (message[x] == '\n' || message[x] == '\r') + continue; + else + temp[count] = message[x]; + count++; + } + + temp = (char*)realloc(temp, count + 1); + temp[count] = 0; + return temp; +} diff --git a/protocols/aim/AIM.h b/protocols/aim/AIM.h new file mode 100644 index 0000000..abdab2c --- /dev/null +++ b/protocols/aim/AIM.h @@ -0,0 +1,58 @@ +/* + * Copyright 2004-2009, IM Kit Team. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef IMKIT_AIM_H +#define IMKIT_AIM_H + +#include +#include +#include + +#include "CayaProtocol.h" +#include "CayaConstants.h" + +#include "imcomm.h" + +class AIMProtocol : public CayaProtocol { +public: + AIMProtocol(); + virtual ~AIMProtocol(); + + virtual status_t Init( CayaProtocolMessengerInterface* ); + virtual status_t Shutdown(); + virtual status_t Process( BMessage * ); + virtual const char * GetSignature(); + virtual const char * GetFriendlySignature(); + virtual status_t UpdateSettings( BMessage & ); + virtual uint32 GetEncoding(); + + static int32 WaitForData(void *); + + static void GotMessage(void *, char *, int, char *); + static void BuddyOnline(void *, char *); + static void BuddyOffline(void *, char *); + static void BuddyAway(void *, char *); + static void BuddyBack(void *, char *); + static void BuddyAwayMsg(void *, char *, char *); + static void BuddyIdle(void *, char *, long); + static void BuddyProfile(void *, char *, char *); + + + + BString fUsername; + BString fPassword; + bool fOnline; + thread_id fIMCommThread; + + void * fIMCommHandle; + + +protected: + status_t A_LogOn(); + status_t LogOff(); + void UnsupportedOperation(); + static char * strip_html (const char *message); +}; + +#endif // IMKIT_AIM_H diff --git a/protocols/aim/Jamfile b/protocols/aim/Jamfile new file mode 100644 index 0000000..de65202 --- /dev/null +++ b/protocols/aim/Jamfile @@ -0,0 +1,23 @@ +SubDir TOP protocols aim ; + +SubDirSysHdrs [ FDirName $(TOP) ] ; +SubDirSysHdrs [ FDirName $(TOP) application ] ; +SubDirSysHdrs [ FDirName $(TOP) libs ] ; +SubDirSysHdrs [ FDirName $(TOP) libs libimcomm ] ; + +SEARCH_SOURCE += [ FDirName $(TOP) protocols aim ] ; + +local sources = + AIM.cpp + main.cpp +; + +AddOn aim : + $(sources) + : libimcomm.a be network $(TARGET_LIBSTDC++) + : aim.rdef +; + +Depends aim : libimcomm.a ; + +InstallBin $(APPS_DIRECTORY)/caya/protocols : aim ; diff --git a/protocols/aim/aim.rdef b/protocols/aim/aim.rdef new file mode 100644 index 0000000..98cf4ee --- /dev/null +++ b/protocols/aim/aim.rdef @@ -0,0 +1,34 @@ + +resource app_version { + major = 0, + middle = 0, + minor = 0, + + variety = B_APPV_ALPHA, + internal = 0, + + short_info = "AIM Protocol for Caya", + long_info = "©2010 Alexander Botero-Lowry" +}; + +resource vector_icon { + $"6E636966080501040046020106023E40000000000000003D4000494000470000" + $"7EFFFFFFFFE5E1DA02000602000000BBC0004000000000009220244AF0000000" + $"33CCFC3366FF02000602000000BA000040000000000092202448800000336699" + $"FF6699CC02000602000000B9000040000000000092202448E00000CC0000FFFF" + $"000002000602000000BA000040000000000092202448800000FF9900FFFBFF00" + $"02000602000000BA000040000000000092202448800000006600FF00CC000A02" + $"06C22622C7562239222E342E2B2E3D4146364441483C50404C3C504A444A4E55" + $"44CBB634CBB83E5E2A0206C22622C7562239222E342E2B2E3D4146364441483C" + $"50404C3C504C464A505744CBB634CBB83E5E2A02024C265928532A583B59335D" + $"350610CAFFFEAF375335543B3B5A3B5A395D325D355D2C5D274F275627483241" + $"2C413541BDA7C2A83942BDA7C2A8394A3F463F463C40324036402A40234F2346" + $"2358325E2A5E395EBF5C5A3F5CBF5C5A3F544053080234313C310404FE372C37" + $"393739373A393B383B3A3B3B393B3A3B390406FE0B4536403640363F363E383E" + $"373E383E393E393E3A403B3F3B413B453A0405FE03453C453445344533433244" + $"324332403240323F323E343E333E3408024D2C4D3C0803553C4F3655300D0A00" + $"01001001178400040A020101000A010102000A0101032021210A010204053021" + $"2101178200040A0102070630212101178200040A010108301D2101178200040A" + $"0102090830212101178200040A030103000A040204051001178200040A050207" + $"061001178200040A060108301C2001178200040A07020908100117820004" +}; diff --git a/protocols/aim/main.cpp b/protocols/aim/main.cpp new file mode 100644 index 0000000..342bb88 --- /dev/null +++ b/protocols/aim/main.cpp @@ -0,0 +1,8 @@ +#include "AIM.h" + +extern "C" __declspec(dllexport) CayaProtocol *main_protocol (); + +CayaProtocol *main_protocol () +{ + return (CayaProtocol *)(new AIMProtocol()); +}