Mercurial > pidgin.yaz
view plugins/icq/icqlib.c @ 1401:bf041349b11e
[gaim-migrate @ 1411]
abliity to set accounts away independent of each other. also allows for all the other states (like in yahoo and icq). probably breaks MSN, so don't use it until rob fixes it.
committer: Tailor Script <tailor@pidgin.im>
author | Eric Warmenhoven <eric@warmenhoven.org> |
---|---|
date | Wed, 10 Jan 2001 22:15:24 +0000 |
parents | 0a766047b4fd |
children | 4c510ca3563f |
line wrap: on
line source
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* $Id: icqlib.c 1319 2000-12-19 10:08:29Z warmenhoven $ $Log$ Revision 1.2 2000/12/19 10:08:29 warmenhoven Yay, new icqlib Revision 1.46 2000/12/19 06:00:07 bills moved members from ICQLINK to ICQLINK_private struct Revision 1.45 2000/11/02 07:29:07 denis Ability to disable TCP protocol has been added. Revision 1.44 2000/07/24 03:10:08 bills added support for real nickname during TCP transactions like file and chat, instead of using Bill all the time (hmm, where'd I get that from? :) Revision 1.43 2000/07/09 22:05:11 bills removed unnecessary functions Revision 1.42 2000/07/09 18:28:07 denis Initial memset() in icq_Init() replaced by callback's clearance. Revision 1.41 2000/06/15 01:50:39 bills removed *Seq functions Revision 1.40 2000/05/10 19:06:59 denis UDP outgoing packet queue was implemented. Revision 1.39 2000/05/03 18:12:36 denis Unfinished UDP queue was commented out. Revision 1.38 2000/04/10 16:36:04 denis Some more Win32 compatibility from Guillaume Rosanis <grs@mail.com> Revision 1.37 2000/04/06 16:38:04 denis icq_*Send*Seq() functions with specified sequence number were added. Revision 1.36 2000/04/05 14:37:02 denis Applied patch from "Guillaume R." <grs@mail.com> for basic Win32 compatibility. Revision 1.35 2000/01/16 03:59:10 bills reworked list code so list_nodes don't need to be inside item structures, removed strlist code and replaced with generic list calls Revision 1.34 1999/12/27 16:06:32 bills cleanups Revision 1.33 1999/10/03 21:35:55 tim Fixed "url" and "descr" parameters order when sending a URL via TCP. Revision 1.32 1999/09/29 16:49:43 denis Host/network/icq byteorder systemized. icq_Init() cleaned up. Revision 1.31 1999/07/18 20:15:55 bills changed to use new byte-order functions & contact list functions Revision 1.30 1999/07/16 12:27:06 denis Other global variables moved to ICQLINK structure. Initialization of random number generator added in icq_Init() Cleaned up. Revision 1.29 1999/07/12 15:13:31 cproch - added definition of ICQLINK to hold session-specific global variabled applications which have more than one connection are now possible - changed nearly every function defintion to support ICQLINK parameter Revision 1.28 1999/07/03 02:26:02 bills added new code to support thruSrv arg to SendMessage and SendURL Revision 1.27 1999/04/17 19:21:37 bills modified Send* Functions to return DWORD instead of WORD Revision 1.26 1999/04/14 14:48:18 denis Switched from icq_Log callback to icq_Fmt function. Cleanups for "strict" compiling (-ansi -pedantic) Revision 1.25 1999/04/05 13:14:57 denis Send messages and URLs to 'not in list' users fixed. Revision 1.24 1999/03/31 01:43:40 bills added TCP support to SendURL Revision 1.23 1999/03/30 22:47:44 lord list of countries now sorted. Revision 1.22 1999/03/28 03:18:22 bills enable tcp messaging in icq_SendMessage, uncommented icq_OurPort and icq_OurIp and fixed function names so icqlib compiles Revision 1.21 1999/03/25 22:16:43 bills added #include "util.h" Revision 1.20 1999/03/24 11:37:36 denis Underscored files with TCP stuff renamed. TCP stuff cleaned up Function names changed to corresponding names. icqlib.c splitted to many small files by subject. C++ comments changed to ANSI C comments. Revision 1.19 1999/03/22 20:51:28 bills added code in icq_HandleUserOnline to set/clear new struct entries in icq_ContactItem; added cleanup code in icq_HandleUserOffline for same Revision 1.18 1999/03/09 13:14:05 denis Cyrillic recoding removed from URLs Revision 1.17 1999/03/05 13:57:54 denis Some cosmetic changes... Revision 1.16 1998/12/08 16:00:59 denis Cleaned up a little before releasing Revision 1.15 1998/11/25 19:18:16 denis Added close icq_ProxySok in icq_Disconnect Revision 1.14 1998/11/25 09:48:49 denis icq_GetProxySok and icq_HandleProxyResponse methods added Connection terminated support added Revision 1.13 1998/11/19 12:22:48 denis SOCKS support cleaned a little icq_RecvUrl renamed to icq_RecvURL icq_ProxyAuth added for Username/Password Authentication URL/Description order inverted icq_Quit splitted to icq_Logout and icq_Disconnect icq_ProxyName and icq_ProxyPass range checking added Revision 1.12 1998/11/18 16:21:29 denis Fixed SOCKS5 proxy support */ #include "icqlib.h" #include <stdlib.h> #ifndef _WIN32 #include <unistd.h> #endif #include <time.h> #ifdef _WIN32 #include <winsock.h> #else #include <netdb.h> #include <sys/socket.h> #endif #include <sys/stat.h> #ifndef _WIN32 #include <sys/time.h> #include <netinet/in.h> #endif #include "util.h" #include "icqtypes.h" #include "icq.h" #include "udp.h" #include "tcp.h" #include "queue.h" int icq_Russian = FALSE; BYTE icq_LogLevel = 0; DWORD icq_SendMessage(ICQLINK *link, DWORD uin, const char *text, BYTE thruSrv) { if(thruSrv==ICQ_SEND_THRUSERVER) return icq_UDPSendMessage(link, uin, text); else if(thruSrv==ICQ_SEND_DIRECT) return icq_TCPSendMessage(link, uin, text); else if(thruSrv==ICQ_SEND_BESTWAY) { icq_ContactItem *pcontact=icq_ContactFind(link, uin); if(pcontact) { if(pcontact->tcp_flag == 0x04) return icq_TCPSendMessage(link, uin, text); else return icq_UDPSendMessage(link, uin, text); } else { return icq_UDPSendMessage(link, uin, text); } } return 0; } DWORD icq_SendURL(ICQLINK *link, DWORD uin, const char *url, const char *descr, BYTE thruSrv) { if(thruSrv==ICQ_SEND_THRUSERVER) return icq_UDPSendURL(link, uin, url, descr); else if(thruSrv==ICQ_SEND_DIRECT) return icq_TCPSendURL(link, uin, descr, url); else if(thruSrv==ICQ_SEND_BESTWAY) { icq_ContactItem *pcontact=icq_ContactFind(link, uin); if(pcontact) { if(pcontact->tcp_flag == 0x04) return icq_TCPSendURL(link, uin, descr, url); else return icq_UDPSendURL(link, uin, url, descr); } else { return icq_UDPSendURL(link, uin, url, descr); } } return 0; } ICQLINK *icq_ICQLINKNew(DWORD uin, const char *password, const char *nick, unsigned char useTCP) { ICQLINK *link = (ICQLINK *)malloc(sizeof(ICQLINK)); link->d = (ICQLINK_private *)malloc(sizeof(ICQLINK_private)); srand(time(0L)); /* memset(link, 0, sizeof(ICQLINK)); */ /* Initialize all callbacks */ link->icq_Logged = 0L; link->icq_Disconnected = 0L; link->icq_RecvMessage = 0L; link->icq_RecvURL = 0L; link->icq_RecvWebPager = 0L; link->icq_RecvMailExpress = 0L; link->icq_RecvChatReq = 0L; link->icq_RecvFileReq = 0L; link->icq_RecvAdded = 0L; link->icq_RecvAuthReq = 0L; link->icq_UserFound = 0L; link->icq_SearchDone = 0L; link->icq_UserOnline = 0L; link->icq_UserOffline = 0L; link->icq_UserStatusUpdate = 0L; link->icq_InfoReply = 0L; link->icq_ExtInfoReply = 0L; link->icq_WrongPassword = 0L; link->icq_InvalidUIN = 0L; link->icq_Log = 0L; link->icq_SrvAck = 0L; link->icq_RequestNotify = 0L; link->icq_NewUIN = 0L; link->icq_SetTimeout = 0L; link->icq_MetaUserFound = 0L; link->icq_MetaUserInfo = 0L; link->icq_MetaUserWork = 0L; link->icq_MetaUserMore = 0L; link->icq_MetaUserAbout = 0L; link->icq_MetaUserInterests = 0L; link->icq_MetaUserAffiliations = 0L; link->icq_MetaUserHomePageCategory = 0L; /* General stuff */ link->icq_Uin = uin; link->icq_Password = strdup(password); link->icq_Nick = strdup(nick); link->icq_OurIP = -1; link->icq_OurPort = 0; link->d->icq_ContactList = list_new(); link->icq_Status = -1; /* UDP stuff */ link->icq_UDPSok = -1; memset(link->d->icq_UDPServMess, FALSE, sizeof(link->d->icq_UDPServMess)); link->d->icq_UDPSeqNum1 = 0; link->d->icq_UDPSeqNum2 = 0; link->d->icq_UDPSession = 0; icq_UDPQueueNew(link); icq_TCPInit(link); link->icq_UseTCP = useTCP; /* Proxy stuff */ link->icq_UseProxy = 0; link->icq_ProxyHost = 0L; link->icq_ProxyIP = -1; link->icq_ProxyPort = 0; link->icq_ProxyAuth = 0; link->icq_ProxyName = 0L; link->icq_ProxyPass = 0L; link->icq_ProxySok = -1; link->icq_ProxyOurPort = 0; link->icq_ProxyDestIP = -1; link->icq_ProxyDestPort = 0; return link; } void icq_ICQLINKDelete(ICQLINK *link) { icq_TCPDone(link); if(link->icq_Password) free(link->icq_Password); if(link->icq_Nick) free(link->icq_Nick); if(link->d->icq_ContactList) list_delete(link->d->icq_ContactList, icq_ContactDelete); icq_UDPQueueDelete(link); free(link->d); free(link); } /****************************** Main function connects gets icq_Uin and icq_Password and logins in and sits in a loop waiting for server responses. *******************************/ void icq_Main(ICQLINK *link) { struct timeval tv; fd_set readfds; tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO(&readfds); FD_SET(link->icq_UDPSok, &readfds); select(link->icq_UDPSok+1, &readfds, 0L, 0L, &tv); if(FD_ISSET(link->icq_UDPSok, &readfds)) icq_HandleServerResponse(link); icq_TCPMain(link); } /********************************** Connects to hostname on port port hostname can be DNS or nnn.nnn.nnn.nnn write out messages to the FD aux ***********************************/ int icq_Connect(ICQLINK *link, const char *hostname, int port) { char buf[1024]; /*, un = 1;*/ /* char tmpbuf[256], our_host[256]*/ int conct, res; unsigned int length; struct sockaddr_in sin, prsin; /* used to store inet addr stuff */ struct hostent *host_struct; /* used in DNS llokup */ link->icq_UDPSok = socket(AF_INET, SOCK_DGRAM, 0);/* create the unconnected socket*/ if(link->icq_UDPSok == -1) { icq_FmtLog(link, ICQ_LOG_FATAL, "Socket creation failed\n"); return -1; } icq_FmtLog(link, ICQ_LOG_MESSAGE, "Socket created attempting to connect\n"); sin.sin_addr.s_addr = INADDR_ANY; sin.sin_family = AF_INET; /* we're using the inet not appletalk*/ sin.sin_port = 0; if(bind(link->icq_UDPSok, (struct sockaddr*)&sin, sizeof(struct sockaddr))<0) { icq_FmtLog(link, ICQ_LOG_FATAL, "Can't bind socket to free port\n"); return -1; } length = sizeof(sin); getsockname(link->icq_UDPSok, (struct sockaddr*)&sin, &length); link->icq_ProxyOurPort = ntohs(sin.sin_port); if(link->icq_UseProxy) { icq_FmtLog(link, ICQ_LOG_MESSAGE, "[SOCKS] Trying to use SOCKS5 proxy\n"); prsin.sin_addr.s_addr = inet_addr(link->icq_ProxyHost); if(prsin.sin_addr.s_addr == (unsigned long)-1) /* name isn't n.n.n.n so must be DNS */ { host_struct = gethostbyname(link->icq_ProxyHost); if(host_struct == 0L) { icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Can't find hostname: %s\n", link->icq_ProxyHost); return -1; } prsin.sin_addr = *((struct in_addr*)host_struct->h_addr); } link->icq_ProxyIP = ntohl(prsin.sin_addr.s_addr); prsin.sin_family = AF_INET; /* we're using the inet not appletalk*/ prsin.sin_port = htons(link->icq_ProxyPort); /* port */ link->icq_ProxySok = socket(AF_INET, SOCK_STREAM, 0);/* create the unconnected socket*/ if(link->icq_ProxySok == -1) { icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Socket creation failed\n"); return -1; } icq_FmtLog(link, ICQ_LOG_MESSAGE, "[SOCKS] Socket created attempting to connect\n"); conct = connect(link->icq_ProxySok, (struct sockaddr *) &prsin, sizeof(prsin)); if(conct == -1) /* did we connect ?*/ { icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Connection refused\n"); return -1; } buf[0] = 5; /* protocol version */ buf[1] = 1; /* number of methods */ if(!strlen(link->icq_ProxyName) || !strlen(link->icq_ProxyPass) || !link->icq_ProxyAuth) buf[2] = 0; /* no authorization required */ else buf[2] = 2; /* method username/password */ #ifdef _WIN32 send(link->icq_ProxySok, buf, 3, 0); res = recv(link->icq_ProxySok, buf, 2, 0); #else write(link->icq_ProxySok, buf, 3); res = read(link->icq_ProxySok, buf, 2); #endif if(strlen(link->icq_ProxyName) && strlen(link->icq_ProxyPass) && link->icq_ProxyAuth) { if(res != 2 || buf[0] != 5 || buf[1] != 2) /* username/password authentication*/ { icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Authentication method incorrect\n"); #ifdef _WIN32 closesocket(link->icq_ProxySok); #else close(link->icq_ProxySok); #endif return -1; } buf[0] = 1; /* version of subnegotiation */ buf[1] = strlen(link->icq_ProxyName); memcpy(&buf[2], link->icq_ProxyName, buf[1]); buf[2+buf[1]] = strlen(link->icq_ProxyPass); memcpy(&buf[3+buf[1]], link->icq_ProxyPass, buf[2+buf[1]]); #ifdef _WIN32 send(link->icq_ProxySok, buf, buf[1]+buf[2+buf[1]]+3, 0); res = recv(link->icq_ProxySok, buf, 2, 0); #else write(link->icq_ProxySok, buf, buf[1]+buf[2+buf[1]]+3); res = read(link->icq_ProxySok, buf, 2); #endif if(res != 2 || buf[0] != 1 || buf[1] != 0) { icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Authorization failure\n"); #ifdef _WIN32 closesocket(link->icq_ProxySok); #else close(link->icq_ProxySok); #endif return -1; } } else { if(res != 2 || buf[0] != 5 || buf[1] != 0) /* no authentication required */ { icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Authentication method incorrect\n"); #ifdef _WIN32 closesocket(link->icq_ProxySok); #else close(link->icq_ProxySok); #endif return -1; } } buf[0] = 5; /* protocol version */ buf[1] = 3; /* command UDP associate */ buf[2] = 0; /* reserved */ buf[3] = 1; /* address type IP v4 */ buf[4] = (char)0; buf[5] = (char)0; buf[6] = (char)0; buf[7] = (char)0; *(unsigned short*)&buf[8] = htons(link->icq_ProxyOurPort); /* memcpy(&buf[8], &link->icq_ProxyOurPort, 2); */ #ifdef _WIN32 send(link->icq_ProxySok, buf, 10, 0); res = recv(link->icq_ProxySok, buf, 10, 0); #else write(link->icq_ProxySok, buf, 10); res = read(link->icq_ProxySok, buf, 10); #endif if(res != 10 || buf[0] != 5 || buf[1] != 0) { switch(buf[1]) { case 1: icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] General SOCKS server failure\n"); break; case 2: icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Connection not allowed by ruleset\n"); break; case 3: icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Network unreachable\n"); break; case 4: icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Host unreachable\n"); break; case 5: icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Connection refused\n"); break; case 6: icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] TTL expired\n"); break; case 7: icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Command not supported\n"); break; case 8: icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Address type not supported\n"); break; default: icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Unknown SOCKS server failure\n"); break; } #ifdef _WIN32 closesocket(link->icq_ProxySok); #else close(link->icq_ProxySok); #endif return -1; } } sin.sin_addr.s_addr = inet_addr(hostname); /* checks for n.n.n.n notation */ if(sin.sin_addr.s_addr == (unsigned long)-1) /* name isn't n.n.n.n so must be DNS */ { host_struct = gethostbyname(hostname); if(host_struct == 0L) { icq_FmtLog(link, ICQ_LOG_FATAL, "Can't find hostname: %s\n", hostname); if(link->icq_UseProxy) { #ifdef _WIN32 closesocket(link->icq_ProxySok); #else close(link->icq_ProxySok); #endif } return -1; } sin.sin_addr = *((struct in_addr *)host_struct->h_addr); } if(link->icq_UseProxy) { link->icq_ProxyDestIP = ntohl(sin.sin_addr.s_addr); memcpy(&sin.sin_addr.s_addr, &buf[4], 4); } sin.sin_family = AF_INET; /* we're using the inet not appletalk*/ sin.sin_port = htons(port); /* port */ if(link->icq_UseProxy) { link->icq_ProxyDestPort = port; memcpy(&sin.sin_port, &buf[8], 2); } conct = connect(link->icq_UDPSok, (struct sockaddr*)&sin, sizeof(sin)); if(conct == -1) /* did we connect ?*/ { icq_FmtLog(link, ICQ_LOG_FATAL, "Connection refused\n"); if(link->icq_UseProxy) { #ifdef _WIN32 closesocket(link->icq_ProxySok); #else close(link->icq_ProxySok); #endif } return -1; } length = sizeof(sin) ; getsockname(link->icq_UDPSok, (struct sockaddr*)&sin, &length); link->icq_OurIP = ntohl(sin.sin_addr.s_addr); link->icq_OurPort = ntohs(sin.sin_port); return link->icq_UDPSok; } void icq_Disconnect(ICQLINK *link) { #ifdef _WIN32 closesocket(link->icq_UDPSok); #else close(link->icq_UDPSok); #endif if(link->icq_UseProxy) { #ifdef _WIN32 closesocket(link->icq_ProxySok); #else close(link->icq_ProxySok); #endif } icq_UDPQueueFree(link); } /* void icq_InitNewUser(const char *hostname, DWORD port) { srv_net_icq_pak pak; int s; struct timeval tv; fd_set readfds; icq_Connect(hostname, port); if((icq_UDPSok == -1) || (icq_UDPSok == 0)) { printf("Couldn't establish connection\n"); exit(1); } icq_RegNewUser(icq_Password); for(;;) { tv.tv_sec = 2; tv.tv_usec = 500000; FD_ZERO(&readfds); FD_SET(icq_UDPSok, &readfds); select(icq_UDPSok+1, &readfds, 0L, 0L, &tv); if(FD_ISSET(icq_UDPSok, &readfds)) { s = icq_UDPSockRead(icq_UDPSok, &pak.head, sizeof(pak)); if(icqtohs(pak.head.cmd) == SRV_NEW_UIN) { icq_Uin = icqtohl(&pak.data[2]); return; } } } } */ /************************ icq_UDPServMess functions *************************/ BOOL icq_GetServMess(ICQLINK *link, WORD num) { return ((link->d->icq_UDPServMess[num/8] & (1 << (num%8))) >> (num%8)); } void icq_SetServMess(ICQLINK *link, WORD num) { link->d->icq_UDPServMess[num/8] |= (1 << (num%8)); } int icq_GetSok(ICQLINK *link) { return link->icq_UDPSok; }