Mercurial > pidgin
view src/protocols/icq/icqlib.c @ 8351:ffa642240fc1
[gaim-migrate @ 9075]
marv is incredibly patient, waiting a long time for this to go in
you should all be using Jabber for file transfer anyway, but if you're
still stuck in the stone age, now you can transfer files via IRC
committer: Tailor Script <tailor@pidgin.im>
author | Nathan Walp <nwalp@pidgin.im> |
---|---|
date | Fri, 27 Feb 2004 01:45:26 +0000 |
parents | 424a40f12a6c |
children |
line wrap: on
line source
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* * $Id: icqlib.c 2096 2001-07-31 01:00:39Z warmenhoven $ * * Copyright (C) 1998-2001, Denis V. Dmitrienko <denis@null.net> and * Bill Soudan <soudan@kde.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "icqlib.h" #include <stdlib.h> #ifdef _WIN32 #include <winsock.h> #else #include <netdb.h> #include <sys/socket.h> #endif #include <sys/stat.h> #include "util.h" #include "icq.h" #include "udp.h" #include "tcp.h" #include "queue.h" #include "socketmanager.h" #include "contacts.h" int icq_Russian = FALSE; BYTE icq_LogLevel = 0; DWORD icq_SendMessage(icq_Link *icqlink, DWORD uin, const char *text, BYTE thruSrv) { if(thruSrv==ICQ_SEND_THRUSERVER) return icq_UDPSendMessage(icqlink, uin, text); else if(thruSrv==ICQ_SEND_DIRECT) return icq_TCPSendMessage(icqlink, uin, text); else if(thruSrv==ICQ_SEND_BESTWAY) { icq_ContactItem *pcontact=icq_ContactFind(icqlink, uin); if(pcontact) { if(pcontact->tcp_flag == 0x04) return icq_TCPSendMessage(icqlink, uin, text); else return icq_UDPSendMessage(icqlink, uin, text); } else { return icq_UDPSendMessage(icqlink, uin, text); } } return 0; } DWORD icq_SendURL(icq_Link *icqlink, DWORD uin, const char *url, const char *descr, BYTE thruSrv) { if(thruSrv==ICQ_SEND_THRUSERVER) return icq_UDPSendURL(icqlink, uin, url, descr); else if(thruSrv==ICQ_SEND_DIRECT) return icq_TCPSendURL(icqlink, uin, descr, url); else if(thruSrv==ICQ_SEND_BESTWAY) { icq_ContactItem *pcontact=icq_ContactFind(icqlink, uin); if(pcontact) { if(pcontact->tcp_flag == 0x04) return icq_TCPSendURL(icqlink, uin, descr, url); else return icq_UDPSendURL(icqlink, uin, url, descr); } else { return icq_UDPSendURL(icqlink, uin, url, descr); } } return 0; } static int icqlib_initialized = 0; void icq_LibInit() { srand(time(0L)); /* initialize internal lists, if necessary */ if (!icq_SocketList) icq_SocketList = icq_ListNew(); if (!icq_TimeoutList) { icq_TimeoutList = icq_ListNew(); icq_TimeoutList->compare_function = (icq_ListCompareFunc)icq_TimeoutCompare; } icqlib_initialized = 1; } icq_Link *icq_LinkNew(DWORD uin, const char *password, const char *nick, unsigned char useTCP) { icq_Link *icqlink = (icq_Link *)malloc(sizeof(icq_Link)); icq_LinkInit(icqlink, uin, password, nick, useTCP); return icqlink; } void icq_LinkInit(icq_Link *icqlink, DWORD uin, const char *password, const char *nick, unsigned char useTCP) { icqlink->d = (icq_LinkPrivate *)malloc(sizeof(icq_LinkPrivate)); if (!icqlib_initialized) icq_LibInit(); /* Initialize all callbacks */ icqlink->icq_Logged = 0L; icqlink->icq_Disconnected = 0L; icqlink->icq_RecvMessage = 0L; icqlink->icq_RecvURL = 0L; icqlink->icq_RecvContactList = 0L; icqlink->icq_RecvWebPager = 0L; icqlink->icq_RecvMailExpress = 0L; icqlink->icq_RecvChatReq = 0L; icqlink->icq_RecvFileReq = 0L; icqlink->icq_RecvAdded = 0L; icqlink->icq_RecvAuthReq = 0L; icqlink->icq_UserFound = 0L; icqlink->icq_SearchDone = 0L; icqlink->icq_UpdateSuccess = 0L; icqlink->icq_UpdateFailure = 0L; icqlink->icq_UserOnline = 0L; icqlink->icq_UserOffline = 0L; icqlink->icq_UserStatusUpdate = 0L; icqlink->icq_InfoReply = 0L; icqlink->icq_ExtInfoReply = 0L; icqlink->icq_WrongPassword = 0L; icqlink->icq_InvalidUIN = 0L; icqlink->icq_Log = 0L; icqlink->icq_SrvAck = 0L; icqlink->icq_RequestNotify = 0L; icqlink->icq_NewUIN = 0L; icqlink->icq_MetaUserFound = 0L; icqlink->icq_MetaUserInfo = 0L; icqlink->icq_MetaUserWork = 0L; icqlink->icq_MetaUserMore = 0L; icqlink->icq_MetaUserAbout = 0L; icqlink->icq_MetaUserInterests = 0L; icqlink->icq_MetaUserAffiliations = 0L; icqlink->icq_MetaUserHomePageCategory = 0L; /* General stuff */ icqlink->icq_Uin = uin; icqlink->icq_Password = strdup(password); icqlink->icq_Nick = strdup(nick); icqlink->icq_OurIP = -1; icqlink->icq_OurPort = 0; icqlink->d->icq_ContactList = icq_ListNew(); icqlink->icq_Status = -1; icqlink->icq_UserData = 0L; /* UDP stuff */ icqlink->icq_UDPSok = -1; memset(icqlink->d->icq_UDPServMess, FALSE, sizeof(icqlink->d->icq_UDPServMess)); icqlink->d->icq_UDPSeqNum1 = 0; icqlink->d->icq_UDPSeqNum2 = 0; icqlink->d->icq_UDPSession = 0; icq_UDPQueueNew(icqlink); /* TCP stuff */ icqlink->icq_UseTCP = useTCP; if (useTCP) icq_TCPInit(icqlink); /* Proxy stuff */ icqlink->icq_UseProxy = 0; icqlink->icq_ProxyHost = 0L; icqlink->icq_ProxyIP = -1; icqlink->icq_ProxyPort = 0; icqlink->icq_ProxyAuth = 0; icqlink->icq_ProxyName = 0L; icqlink->icq_ProxyPass = 0L; icqlink->icq_ProxySok = -1; icqlink->icq_ProxyOurPort = 0; icqlink->icq_ProxyDestIP = -1; icqlink->icq_ProxyDestPort = 0; } void icq_LinkDestroy(icq_Link *icqlink) { if(icqlink->icq_UseTCP) icq_TCPDone(icqlink); if(icqlink->icq_Password) free(icqlink->icq_Password); if(icqlink->icq_Nick) free(icqlink->icq_Nick); if(icqlink->d->icq_ContactList) icq_ListDelete(icqlink->d->icq_ContactList, icq_ContactDelete); icq_UDPQueueDelete(icqlink); free(icqlink->d); } void icq_LinkDelete(icq_Link *icqlink) { icq_LinkDestroy(icqlink); free(icqlink); } /****************************** Main function connects gets icq_Uin and icq_Password and logins in and sits in a loop waiting for server responses. *******************************/ void icq_Main() { icq_SocketPoll(); } /********************************** 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(icq_Link *icqlink, 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 saddr, prsin; /* used to store inet addr stuff */ struct hostent *host_struct; /* used in DNS llokup */ /* create the unconnected socket*/ icqlink->icq_UDPSok = icq_SocketNew(AF_INET, SOCK_DGRAM, 0); if(icqlink->icq_UDPSok == -1) { icq_FmtLog(icqlink, ICQ_LOG_FATAL, "Socket creation failed\n"); return -1; } icq_FmtLog(icqlink, ICQ_LOG_MESSAGE, "Socket created attempting to connect\n"); saddr.sin_addr.s_addr = INADDR_ANY; saddr.sin_family = AF_INET; /* we're using the inet not appletalk*/ saddr.sin_port = 0; if(bind(icqlink->icq_UDPSok, (struct sockaddr*)&saddr, sizeof(struct sockaddr))<0) { icq_FmtLog(icqlink, ICQ_LOG_FATAL, "Can't bind socket to free port\n"); icq_SocketDelete(icqlink->icq_UDPSok); icqlink->icq_UDPSok = -1; return -1; } length = sizeof(saddr); getsockname(icqlink->icq_UDPSok, (struct sockaddr*)&saddr, &length); icqlink->icq_ProxyOurPort = ntohs(saddr.sin_port); if(icqlink->icq_UseProxy) { int hasName = icqlink->icq_ProxyName && strlen(icqlink->icq_ProxyName); int hasPass = icqlink->icq_ProxyPass && strlen(icqlink->icq_ProxyPass); int authEnabled = icqlink->icq_ProxyAuth && hasName && hasPass; icq_FmtLog(icqlink, ICQ_LOG_MESSAGE, "[SOCKS] Trying to use SOCKS5 proxy\n"); prsin.sin_addr.s_addr = inet_addr(icqlink->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(icqlink->icq_ProxyHost); if(host_struct == 0L) { icq_FmtLog(icqlink, ICQ_LOG_FATAL, "[SOCKS] Can't find hostname: %s\n", icqlink->icq_ProxyHost); return -1; } prsin.sin_addr = *((struct in_addr*)host_struct->h_addr); } icqlink->icq_ProxyIP = ntohl(prsin.sin_addr.s_addr); prsin.sin_family = AF_INET; /* we're using the inet not appletalk*/ prsin.sin_port = htons(icqlink->icq_ProxyPort); /* port */ /* create the unconnected socket*/ icqlink->icq_ProxySok = icq_SocketNew(AF_INET, SOCK_STREAM, 0); if(icqlink->icq_ProxySok == -1) { icq_FmtLog(icqlink, ICQ_LOG_FATAL, "[SOCKS] Socket creation failed\n"); return -1; } icq_FmtLog(icqlink, ICQ_LOG_MESSAGE, "[SOCKS] Socket created attempting to connect\n"); conct = connect(icqlink->icq_ProxySok, (struct sockaddr *) &prsin, sizeof(prsin)); if(conct == -1) /* did we connect ?*/ { icq_FmtLog(icqlink, ICQ_LOG_FATAL, "[SOCKS] Connection refused\n"); return -1; } buf[0] = 5; /* protocol version */ buf[1] = 1; /* number of methods */ buf[2] = authEnabled ? 2 : 0; /* authentication method */ #ifdef _WIN32 send(icqlink->icq_ProxySok, buf, 3, 0); res = recv(icqlink->icq_ProxySok, buf, 2, 0); #else write(icqlink->icq_ProxySok, buf, 3); res = read(icqlink->icq_ProxySok, buf, 2); #endif if(authEnabled) { if(res != 2 || buf[0] != 5 || buf[1] != 2) /* username/password authentication*/ { icq_FmtLog(icqlink, ICQ_LOG_FATAL, "[SOCKS] Authentication method incorrect\n"); icq_SocketDelete(icqlink->icq_ProxySok); return -1; } buf[0] = 1; /* version of subnegotiation */ buf[1] = strlen(icqlink->icq_ProxyName); memcpy(&buf[2], icqlink->icq_ProxyName, buf[1]); buf[2+buf[1]] = strlen(icqlink->icq_ProxyPass); memcpy(&buf[3+buf[1]], icqlink->icq_ProxyPass, buf[2+buf[1]]); #ifdef _WIN32 send(icqlink->icq_ProxySok, buf, buf[1]+buf[2+buf[1]]+3, 0); res = recv(icqlink->icq_ProxySok, buf, 2, 0); #else write(icqlink->icq_ProxySok, buf, buf[1]+buf[2+buf[1]]+3); res = read(icqlink->icq_ProxySok, buf, 2); #endif if(res != 2 || buf[0] != 1 || buf[1] != 0) { icq_FmtLog(icqlink, ICQ_LOG_FATAL, "[SOCKS] Authorization failure\n"); icq_SocketDelete(icqlink->icq_ProxySok); return -1; } } else { if(res != 2 || buf[0] != 5 || buf[1] != 0) /* no authentication required */ { icq_FmtLog(icqlink, ICQ_LOG_FATAL, "[SOCKS] Authentication method incorrect\n"); icq_SocketDelete(icqlink->icq_ProxySok); 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(icqlink->icq_ProxyOurPort); /* memcpy(&buf[8], &icqlink->icq_ProxyOurPort, 2); */ #ifdef _WIN32 send(icqlink->icq_ProxySok, buf, 10, 0); res = recv(icqlink->icq_ProxySok, buf, 10, 0); #else write(icqlink->icq_ProxySok, buf, 10); res = read(icqlink->icq_ProxySok, buf, 10); #endif if(res != 10 || buf[0] != 5 || buf[1] != 0) { switch(buf[1]) { case 1: icq_FmtLog(icqlink, ICQ_LOG_FATAL, "[SOCKS] General SOCKS server failure\n"); break; case 2: icq_FmtLog(icqlink, ICQ_LOG_FATAL, "[SOCKS] Connection not allowed by ruleset\n"); break; case 3: icq_FmtLog(icqlink, ICQ_LOG_FATAL, "[SOCKS] Network unreachable\n"); break; case 4: icq_FmtLog(icqlink, ICQ_LOG_FATAL, "[SOCKS] Host unreachable\n"); break; case 5: icq_FmtLog(icqlink, ICQ_LOG_FATAL, "[SOCKS] Connection refused\n"); break; case 6: icq_FmtLog(icqlink, ICQ_LOG_FATAL, "[SOCKS] TTL expired\n"); break; case 7: icq_FmtLog(icqlink, ICQ_LOG_FATAL, "[SOCKS] Command not supported\n"); break; case 8: icq_FmtLog(icqlink, ICQ_LOG_FATAL, "[SOCKS] Address type not supported\n"); break; default: icq_FmtLog(icqlink, ICQ_LOG_FATAL, "[SOCKS] Unknown SOCKS server failure\n"); break; } icq_SocketDelete(icqlink->icq_ProxySok); icqlink->icq_ProxySok = -1; return -1; } } saddr.sin_addr.s_addr = inet_addr(hostname); /* checks for n.n.n.n notation */ if(saddr.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(icqlink, ICQ_LOG_FATAL, "Can't find hostname: %s\n", hostname); if(icqlink->icq_UseProxy) { icq_SocketDelete(icqlink->icq_ProxySok); } return -1; } saddr.sin_addr = *((struct in_addr *)host_struct->h_addr); } if(icqlink->icq_UseProxy) { icqlink->icq_ProxyDestIP = ntohl(saddr.sin_addr.s_addr); memcpy(&saddr.sin_addr.s_addr, &buf[4], 4); } saddr.sin_family = AF_INET; /* we're using the inet not appletalk*/ saddr.sin_port = htons(port); /* port */ if(icqlink->icq_UseProxy) { icqlink->icq_ProxyDestPort = port; memcpy(&saddr.sin_port, &buf[8], 2); } conct = connect(icqlink->icq_UDPSok, (struct sockaddr*)&saddr, sizeof(saddr)); if(conct == -1) /* did we connect ?*/ { icq_FmtLog(icqlink, ICQ_LOG_FATAL, "Connection refused\n"); if(icqlink->icq_UseProxy) { icq_SocketDelete(icqlink->icq_ProxySok); } return -1; } length = sizeof(saddr) ; getsockname(icqlink->icq_UDPSok, (struct sockaddr*)&saddr, &length); icqlink->icq_OurIP = ntohl(saddr.sin_addr.s_addr); icqlink->icq_OurPort = ntohs(saddr.sin_port); /* sockets are ready to receive data - install handlers */ icq_SocketSetHandler(icqlink->icq_UDPSok, ICQ_SOCKET_READ, (icq_SocketHandler)icq_HandleServerResponse, icqlink); if (icqlink->icq_UseProxy) icq_SocketSetHandler(icqlink->icq_ProxySok, ICQ_SOCKET_READ, (icq_SocketHandler)icq_HandleProxyResponse, icqlink); return icqlink->icq_UDPSok; } void icq_Disconnect(icq_Link *icqlink) { icq_SocketDelete(icqlink->icq_UDPSok); if(icqlink->icq_UseProxy) icq_SocketDelete(icqlink->icq_ProxySok); icq_UDPQueueFree(icqlink); } /* 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(icq_Link *icqlink, WORD num) { return ((icqlink->d->icq_UDPServMess[num/8] & (1 << (num%8))) >> (num%8)); } void icq_SetServMess(icq_Link *icqlink, WORD num) { icqlink->d->icq_UDPServMess[num/8] |= (1 << (num%8)); } int icq_GetSok(icq_Link *icqlink) { return icqlink->icq_UDPSok; }