Mercurial > pidgin
view src/protocols/icq/tcplink.c @ 6629:bdc448cf4cb6
[gaim-migrate @ 7153]
Tim Ringenbach (marv_sf) writes:
" This patch makes sending colors in yahoo work. It also
makes a few changing to receiving them, and addresses
most of the problems with that patch (which I think
were all related to the fact it didn't do outgoing colors).
It now handles bold, italic, underline, font face, font
size, and font color in both directions. It disables
the background color button if the prpl is yahoo (in a
generic way), and farthermore strips out any <body>
tags that the user might try to type anyway (the yahoo
server purposely mangles them).
It also adds a line to g_strescape some debug messages
because I got tired them of changing the color of my
terminal.
I think I got all the bugs out. If you run with -d or
open the debug window, it will show you what both
conversion function returned, which should help track
down any problems."
committer: Tailor Script <tailor@pidgin.im>
author | Luke Schierer <lschiere@pidgin.im> |
---|---|
date | Tue, 26 Aug 2003 01:34:51 +0000 |
parents | f0a2a9afdb77 |
children |
line wrap: on
line source
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* * $Id: tcplink.c 2509 2001-10-13 00:06:18Z 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 <stdlib.h> #include <fcntl.h> #include <errno.h> #ifdef _WIN32 #include <winsock.h> #define EINPROGRESS WSAEINPROGRESS #define ENETUNREACH WSAENETUNREACH #define ECONNREFUSED WSAECONNREFUSED #define ETIMEDOUT WSAETIMEDOUT #define EOPNOTSUPP WSAEOPNOTSUPP #define EAFNOSUPPORT WSAEAFNOSUPPORT #define EWOULDBLOCK WSAEWOULDBLOCK #else #include <netdb.h> #endif #include "icqlib.h" #include "stdpackets.h" #include "tcp.h" #include "errno.h" #include "chatsession.h" #include "filesession.h" #include "contacts.h" #include "socketmanager.h" icq_TCPLink *icq_TCPLinkNew(icq_Link *icqlink) { icq_TCPLink *p=(icq_TCPLink *)malloc(sizeof(icq_TCPLink)); p->socket=-1; p->icqlink=icqlink; p->mode=0; p->session=0L; p->type=TCP_LINK_MESSAGE; p->buffer_count=0; p->send_queue=icq_ListNew(); p->received_queue=icq_ListNew(); p->id=0; p->remote_uin=0; p->remote_version=0; p->flags=0; p->proxy_status = 0; p->connect_timeout = NULL; if(p) icq_ListEnqueue(icqlink->d->icq_TCPLinks, p); return p; } int _icq_TCPLinkDelete(void *pv, va_list data) { icq_Packet *p=(icq_Packet *)pv; icq_Link *icqlink=va_arg(data, icq_Link *); /* notify the app the packet didn't make it */ if(p->id) invoke_callback(icqlink, icq_RequestNotify)(icqlink, p->id, ICQ_NOTIFY_FAILED, 0, 0); return 0; } void icq_TCPLinkDelete(void *pv) { icq_TCPLink *p=(icq_TCPLink *)pv; /* process anything left in the received queue */ icq_TCPLinkProcessReceived(p); /* make sure we notify app that packets in send queue didn't make it */ (void)icq_ListTraverse(p->send_queue, _icq_TCPLinkDelete, p->icqlink); /* destruct all packets still waiting on queues */ icq_ListDelete(p->send_queue, icq_PacketDelete); icq_ListDelete(p->received_queue, icq_PacketDelete); /* if this is a chat or file link, delete the associated session as * well, but make sure we unassociate ourself first so the session * doesn't try to close us */ if(p->session) { if(p->type==TCP_LINK_CHAT) { icq_ChatSession *psession=p->session; psession->tcplink=NULL; icq_ChatSessionClose(psession); } if(p->type==TCP_LINK_FILE) { icq_FileSession *psession=p->session; psession->tcplink=NULL; icq_FileSessionClose(psession); } } /* close the socket after we notify app so app can read errno if necessary */ if (p->socket > -1) { icq_SocketDelete(p->socket); } if (p->connect_timeout) { icq_TimeoutDelete(p->connect_timeout); } free(p); } void icq_TCPLinkClose(icq_TCPLink *plink) { icq_ListRemove(plink->icqlink->d->icq_TCPLinks, plink); icq_TCPLinkDelete(plink); } int icq_TCPLinkProxyConnect(icq_TCPLink *plink, DWORD uin, int port) { struct sockaddr_in prsin; struct hostent *host_struct; int conct; (void)uin; (void)port; prsin.sin_addr.s_addr = htonl(plink->icqlink->icq_ProxyIP); if(prsin.sin_addr.s_addr == (unsigned long)-1) { prsin.sin_addr.s_addr = inet_addr(plink->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(plink->icqlink->icq_ProxyHost); if(host_struct == 0L) { icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Can't find hostname: %s\n", plink->icqlink->icq_ProxyHost); return -1; } prsin.sin_addr = *((struct in_addr *)host_struct->h_addr); } } prsin.sin_family = AF_INET; /* we're using the inet not appletalk*/ prsin.sin_port = htons(plink->icqlink->icq_ProxyPort); /* port */ /* flags = fcntl(plink->socket, F_GETFL, 0); */ /* fcntl(plink->socket, F_SETFL, flags & (~O_NONBLOCK)); */ plink->mode |= TCP_LINK_SOCKS_CONNECTING; conct = connect(plink->socket, (struct sockaddr *) &prsin, sizeof(prsin)); if(conct == -1) /* did we connect ?*/ { if(errno != EINPROGRESS) { conct = errno; icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Connection refused\n"); return conct; } return 1; } return 0; } int icq_TCPLinkProxyRequestAuthorization(icq_TCPLink *plink) { char buf[1024]; int hasName = plink->icqlink->icq_ProxyName && strlen(plink->icqlink->icq_ProxyName); int hasPass = plink->icqlink->icq_ProxyPass && strlen(plink->icqlink->icq_ProxyPass); int authEnabled = hasName && hasPass && plink->icqlink->icq_ProxyAuth; plink->mode = (plink->mode & (~TCP_LINK_SOCKS_CONNECTING)); buf[0] = 5; /* protocol version */ buf[1] = 1; /* number of methods */ buf[2] = authEnabled ? 2 : 0; /* authentication method */ plink->mode |= authEnabled ? TCP_LINK_SOCKS_AUTHORIZATION : TCP_LINK_SOCKS_NOAUTHSTATUS; #ifdef _WIN32 if(send(plink->socket, buf, 3, 0) != 3) return errno; #else if(write(plink->socket, buf, 3) != 3) return errno; #endif return 0; } int icq_TCPLinkProxyAuthorization(icq_TCPLink *plink) { int res; char buf[1024]; plink->mode &= ~TCP_LINK_SOCKS_AUTHORIZATION; plink->mode |= TCP_LINK_SOCKS_AUTHSTATUS; #ifdef _WIN32 res = recv(plink->socket, buf, 2, 0); #else res = read(plink->socket, buf, 2); #endif if(res != 2 || buf[0] != 5 || buf[1] != 2) /* username/password authentication*/ { icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Authentication method incorrect\n"); icq_SocketDelete(plink->socket); return -1; } buf[0] = 1; /* version of subnegotiation */ buf[1] = strlen(plink->icqlink->icq_ProxyName); memcpy(&buf[2], plink->icqlink->icq_ProxyName, buf[1]); buf[2+buf[1]] = strlen(plink->icqlink->icq_ProxyPass); memcpy(&buf[3+buf[1]], plink->icqlink->icq_ProxyPass, buf[2+buf[1]]); #ifdef _WIN32 if(send(plink->socket, buf, buf[1]+buf[2+buf[1]]+3, 0) != buf[1] + buf[2+buf[1]]+3) return errno; #else if(write(plink->socket, buf, buf[1]+buf[2+buf[1]]+3) != buf[1] + buf[2+buf[1]]+3) return errno; #endif return 0; } int icq_TCPLinkProxyAuthStatus(icq_TCPLink *plink) { int res; char buf[20]; plink->mode = (plink->mode & (~TCP_LINK_SOCKS_AUTHSTATUS)) | TCP_LINK_SOCKS_CROSSCONNECT; #ifdef _WIN32 res = recv(plink->socket, buf, 2, 0); #else res = read(plink->socket, buf, 2); #endif if(res != 2 || buf[0] != 1 || buf[1] != 0) { icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Authorization failure\n"); icq_SocketDelete(plink->socket); return -1; } return 0; } int icq_TCPLinkProxyNoAuthStatus(icq_TCPLink *plink) { int res; char buf[20]; plink->mode = (plink->mode & (~TCP_LINK_SOCKS_NOAUTHSTATUS)) | TCP_LINK_SOCKS_CROSSCONNECT; #ifdef _WIN32 res = recv(plink->socket, buf, 2, 0); #else res = read(plink->socket, buf, 2); #endif if(res != 2 || buf[0] != 5 || buf[1] != 0) /* no authentication required */ { icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Authentication method incorrect\n"); icq_SocketDelete(plink->socket); return -1; } return 0; } int icq_TCPLinkProxyCrossConnect(icq_TCPLink *plink) { char buf[20]; plink->mode = (plink->mode & ~(TCP_LINK_SOCKS_CROSSCONNECT)) | TCP_LINK_SOCKS_CONNSTATUS; buf[0] = 5; /* protocol version */ buf[1] = 1; /* command connect */ buf[2] = 0; /* reserved */ buf[3] = 1; /* address type IP v4 */ memcpy(&buf[4], &plink->remote_address.sin_addr.s_addr, 4); memcpy(&buf[8], &plink->remote_address.sin_port, 2); #ifdef _WIN32 if(send(plink->socket, buf, 10, 0) != 10) return errno; #else if(write(plink->socket, buf, 10) != 10) return errno; #endif return 0; } int icq_TCPLinkProxyConnectStatus(icq_TCPLink *plink) { int res; char buf[1024]; plink->mode = (plink->mode & (~TCP_LINK_SOCKS_CONNSTATUS)); #ifdef _WIN32 res = recv(plink->socket, buf, 10, 0); #else res = read(plink->socket, buf, 10); #endif if(res != 10 || buf[0] != 5 || buf[1] != 0) { switch(buf[1]) { case 1: icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] General SOCKS server failure\n"); res = EFAULT; break; case 2: icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Connection not allowed by ruleset\n"); res = EACCES; break; case 3: icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Network unreachable\n"); res = ENETUNREACH; break; case 4: icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Host unreachable\n"); res = ENETUNREACH; break; case 5: icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Connection refused\n"); res = ECONNREFUSED; break; case 6: icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] TTL expired\n"); res = ETIMEDOUT; break; case 7: icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Command not supported\n"); res = EOPNOTSUPP; break; case 8: icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Address type not supported\n"); res = EAFNOSUPPORT; break; default: icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Unknown SOCKS server failure\n"); res = EFAULT; break; } icq_SocketDelete(plink->socket); return res; } return 0; } int icq_TCPLinkConnect(icq_TCPLink *plink, DWORD uin, int port) { icq_ContactItem *pcontact=icq_ContactFind(plink->icqlink, uin); icq_Packet *p; int result; #ifndef _WIN32 int flags; #else u_long iosflag; #endif /* these return values never and nowhere checked */ /* denis. */ if(!pcontact) return -2; if((plink->socket=icq_SocketNew(AF_INET, SOCK_STREAM, 0)) < 0) return -3; /* bzero(&(plink->remote_address), sizeof(plink->remote_address)); Win32 incompatible... */ memset(&(plink->remote_address), 0, sizeof(plink->remote_address)); plink->remote_address.sin_family = AF_INET; /* if our IP is the same as the remote user's ip, connect to real_ip instead since we're both probably behind a firewall */ icq_FmtLog(plink->icqlink, ICQ_LOG_MESSAGE, "local IP is %08X:%d, remote real IP is %08X:%d, remote IP is %08X:%d, port is %d\n", plink->icqlink->icq_OurIP, plink->icqlink->icq_OurPort, pcontact->remote_real_ip, pcontact->remote_port, pcontact->remote_ip, pcontact->remote_port, port ); if (plink->icqlink->icq_OurIP == pcontact->remote_ip) plink->remote_address.sin_addr.s_addr = htonl(pcontact->remote_real_ip); else plink->remote_address.sin_addr.s_addr = htonl(pcontact->remote_ip); if(plink->type==TCP_LINK_MESSAGE) { plink->remote_address.sin_port = htons(pcontact->remote_port); icq_FmtLog(plink->icqlink, ICQ_LOG_MESSAGE, "initiating message connect to %d (%s:%d)\n", uin, inet_ntoa(*((struct in_addr *)(&(plink->remote_address.sin_addr)))), pcontact->remote_port); } else { plink->remote_address.sin_port = htons(port); icq_FmtLog(plink->icqlink, ICQ_LOG_MESSAGE, "initiating file/chat connect to %d (%s:%d)\n", uin, inet_ntoa(*((struct in_addr *)(&(plink->remote_address.sin_addr)))), port); } /* set the socket to non-blocking */ #ifdef _WIN32 iosflag = TRUE; ioctlsocket(plink->socket, FIONBIO, &iosflag); #else flags=fcntl(plink->socket, F_GETFL, 0); fcntl(plink->socket, F_SETFL, flags | O_NONBLOCK); #endif if(!plink->icqlink->icq_UseProxy) result=connect(plink->socket, (struct sockaddr *)&(plink->remote_address), sizeof(plink->remote_address)); else /* SOCKS proxy support */ result=icq_TCPLinkProxyConnect(plink, uin, port); /* FIXME: Here we should check for errors on connection */ /* because of proxy support - it can't be checked */ /* by getsockopt() later in _handle_ready_sockets() */ /* denis. */ plink->mode|=TCP_LINK_MODE_CONNECTING; plink->remote_uin=uin; /* Send the hello packet */ p=icq_TCPCreateInitPacket(plink); icq_TCPLinkSend(plink, p); #ifdef TCP_PACKET_TRACE printf("hello packet queued for %lu\n", uin); #endif /* TCP_PACKET_TRACE */ icq_SocketSetHandler(plink->socket, ICQ_SOCKET_WRITE, (icq_SocketHandler)icq_TCPLinkOnConnect, plink); plink->connect_timeout=icq_TimeoutNew(TCP_LINK_CONNECT_TIMEOUT, (icq_TimeoutHandler)icq_TCPLinkClose, plink); return 1; } icq_TCPLink *icq_TCPLinkAccept(icq_TCPLink *plink) { #ifdef _WIN32 u_long iosflag; #else int flags; #endif int socket_fd; size_t remote_length; icq_TCPLink *pnewlink=icq_TCPLinkNew(plink->icqlink); if(pnewlink) { remote_length = sizeof(struct sockaddr_in); socket_fd=icq_SocketAccept(plink->socket, (struct sockaddr *)&(plink->remote_address), &remote_length); icq_FmtLog(plink->icqlink, ICQ_LOG_MESSAGE, "accepting tcp connection from %s:%d\n", inet_ntoa(*((struct in_addr *)(&(plink->remote_address.sin_addr)))), ntohs(plink->remote_address.sin_port)); /* FIXME: make sure accept succeeded */ pnewlink->type=plink->type; pnewlink->socket=socket_fd; /* first packet sent on an icq tcp link is always the hello packet */ pnewlink->mode|=TCP_LINK_MODE_HELLOWAIT; /* install socket handler for new socket */ icq_SocketSetHandler(socket_fd, ICQ_SOCKET_READ, (icq_SocketHandler)icq_TCPLinkOnDataReceived, pnewlink); } /* set the socket to non-blocking */ #ifdef _WIN32 iosflag = TRUE; ioctlsocket(pnewlink->socket, FIONBIO, &iosflag); #else flags=fcntl(pnewlink->socket, F_GETFL, 0); fcntl(pnewlink->socket, F_SETFL, flags | O_NONBLOCK); #endif return pnewlink; } int icq_TCPLinkListen(icq_TCPLink *plink) { unsigned int t; /* listening links have 0 uin */ plink->remote_uin=0; /* create tcp listen socket */ if((plink->socket=icq_SocketNew(AF_INET, SOCK_STREAM, 0)) < 0) return -1; /* must use memset, no bzero for Win32! */ memset(&plink->socket_address, 0, sizeof(struct sockaddr_in)); plink->socket_address.sin_family=AF_INET; plink->socket_address.sin_addr.s_addr=htonl(INADDR_ANY); plink->socket_address.sin_port=0; if(bind(plink->socket, (struct sockaddr *)&plink->socket_address, sizeof(struct sockaddr_in)) < 0) return -2; if(listen(plink->socket, 5) < 0) return -3; t=sizeof(struct sockaddr_in); if(getsockname(plink->socket, (struct sockaddr *)&plink->socket_address, &t) < 0) return -4; icq_FmtLog(plink->icqlink, ICQ_LOG_MESSAGE, "created tcp listening socket %d, local address=%s:%d\n", plink->socket, inet_ntoa(*((struct in_addr *)(&plink->socket_address.sin_addr))), ntohs(plink->socket_address.sin_port)); plink->mode|=TCP_LINK_MODE_LISTEN; icq_SocketSetHandler(plink->socket, ICQ_SOCKET_READ, (icq_SocketHandler)icq_TCPLinkAccept, plink); return 0; } /* Doing Cyrillic translations for Chat dialog sessions */ void icq_ChatRusConv_n(const char to[4], char *t_in, int t_len) { int i, j; for(i = j = 0; i < t_len; ++i) { if((((unsigned char)t_in[i]) < ' ') && (t_in[i] != '\r')) { if(i - 1 > j) icq_RusConv_n(to, &t_in[j], i - j - 1); switch(t_in[i]) { case '\x07': /* Bell */ case '\x08': /* BackSpace */ case '\x03': /* Chat is active */ case '\x04': /* Chat is not active */ break; case '\x00': /* Foregroung color (RR GG BB ?? ) */ case '\x01': /* Background color (RR GG BB ?? ) */ case '\x11': /* Font style change (Bold - 1, Italic - 2, Underline - 4) */ case '\x12': /* Font size change */ i += 4; break; case '\x10': /* Font family and encoding change */ i += t_in[i+1] + 2 + 2; icq_RusConv_n(to, &t_in[i+3], t_in[i+1]); break; } j = i + 1; } } if(i > t_len) i = t_len; if(j > t_len) j = t_len; if(i > j) icq_RusConv_n(to, &t_in[j], i - j); } void icq_TCPLinkOnDataReceived(icq_TCPLink *plink) { int process_count=0, recv_result=0; char *buffer=plink->buffer; do { /* while recv_result > 0 */ int done=0; /* append received data onto end of buffer */ if((recv_result=recv(plink->socket, buffer+plink->buffer_count, icq_TCPLinkBufferSize-plink->buffer_count, 0)) < 1) { /* either there was an error or the remote side has closed * the connection - fall out of the loop */ continue; }; plink->buffer_count+=recv_result; #ifdef TCP_BUFFER_TRACE printf("received %d bytes from link %x, new buffer count %d\n", recv_result, plink, plink->buffer_count); hex_dump(plink->buffer, plink->buffer_count); #endif /*TCP_BUFFER_TRACE*/ process_count+=recv_result; /* don't do any packet processing if we're in raw mode */ if(plink->mode & TCP_LINK_MODE_RAW) { /* notify the app with the new data */ if(plink->type == TCP_LINK_CHAT) icq_ChatRusConv_n("wk", plink->buffer, plink->buffer_count); invoke_callback(plink->icqlink, icq_ChatNotify)(plink->session, CHAT_NOTIFY_DATA, plink->buffer_count, plink->buffer); plink->buffer_count=0; continue; } /* remove packets from the buffer until the buffer is empty * or the remaining bytes do not equal a full packet */ while((unsigned)plink->buffer_count>sizeof(WORD) && !done) { WORD packet_size=(*((WORD *)buffer)); /* warn if the buffer is too small to hold the whole packet */ if(packet_size>icq_TCPLinkBufferSize-sizeof(WORD)) { icq_FmtLog(plink->icqlink, ICQ_LOG_WARNING, "tcplink buffer " "overflow, packet size = %d, buffer size = %d, closing link\n", packet_size, icq_TCPLinkBufferSize); return; } if(packet_size+sizeof(WORD) <= (unsigned)plink->buffer_count) { /* copy the packet into memory */ icq_Packet *p=icq_PacketNew(); icq_PacketAppend(p, buffer+sizeof(WORD), packet_size); /* remove it from the buffer */ memcpy(buffer, buffer+packet_size+sizeof(WORD), plink->buffer_count-packet_size-sizeof(WORD)); plink->buffer_count-=(packet_size+sizeof(WORD)); icq_TCPLinkOnPacketReceived(plink, p); } else { /* not enough bytes in buffer to form the complete packet. * we're done for now */ done=1; } } /* while packets remain in buffer */ } while (recv_result > 0); #ifdef _WIN32 if (recv_result <= 0 && WSAGetLastError()!=EWOULDBLOCK) { /* receive error - log it */ icq_FmtLog(plink->icqlink, ICQ_LOG_WARNING, "recv failed from %d (%d)," " closing link\n", plink->remote_uin, WSAGetLastError()); #else if (recv_result <= 0 && errno!=EWOULDBLOCK) { /* receive error - log it */ icq_FmtLog(plink->icqlink, ICQ_LOG_WARNING, "recv failed from %d (%d-%s)," " closing link\n", plink->remote_uin, errno, strerror(errno)); #endif icq_TCPLinkClose(plink); } else { icq_TCPLinkProcessReceived(plink); } } void icq_TCPLinkOnPacketReceived(icq_TCPLink *plink, icq_Packet *p) { #ifdef TCP_RAW_TRACE printf("packet received! { length=%d }\n", p->length); icq_PacketDump(p); #endif /* Stick packet on ready packet linked icq_List */ icq_ListEnqueue(plink->received_queue, p); } void icq_TCPLinkOnConnect(icq_TCPLink *plink) { #ifdef _WIN32 int len; #else size_t len; #endif int error; icq_TimeoutDelete(plink->connect_timeout); plink->connect_timeout = NULL; /* check getsockopt */ len=sizeof(error); #ifndef __BEOS__ #ifdef _WIN32 getsockopt(plink->socket, SOL_SOCKET, SO_ERROR, (char *)&error, &len); #else getsockopt(plink->socket, SOL_SOCKET, SO_ERROR, &error, &len); #endif #endif if(!error && (plink->mode & (TCP_LINK_SOCKS_CONNECTING | TCP_LINK_SOCKS_AUTHORIZATION | TCP_LINK_SOCKS_AUTHSTATUS | TCP_LINK_SOCKS_NOAUTHSTATUS | TCP_LINK_SOCKS_CROSSCONNECT | TCP_LINK_SOCKS_CONNSTATUS))) { if(plink->mode & TCP_LINK_SOCKS_CONNECTING) error = icq_TCPLinkProxyRequestAuthorization(plink); else if(plink->mode & TCP_LINK_SOCKS_AUTHORIZATION) error = icq_TCPLinkProxyAuthorization(plink); else if(plink->mode & TCP_LINK_SOCKS_AUTHSTATUS) error = icq_TCPLinkProxyAuthStatus(plink); else if(plink->mode & TCP_LINK_SOCKS_NOAUTHSTATUS) error = icq_TCPLinkProxyNoAuthStatus(plink); else if(plink->mode & TCP_LINK_SOCKS_CROSSCONNECT) error = icq_TCPLinkProxyCrossConnect(plink); else if(plink->mode & TCP_LINK_SOCKS_CONNSTATUS) error = icq_TCPLinkProxyConnectStatus(plink); else error = EINVAL; } if(error) { /* connection failed- close the link, which takes care * of notifying the app about packets that didn't make it */ icq_FmtLog(plink->icqlink, ICQ_LOG_WARNING, "connect failed to %d (%d-%s)," " closing link\n", plink->remote_uin, error, strerror(error)); icq_TCPLinkClose(plink); return; } if(plink->mode & (TCP_LINK_SOCKS_CONNECTING | TCP_LINK_SOCKS_AUTHORIZATION | TCP_LINK_SOCKS_AUTHSTATUS | TCP_LINK_SOCKS_NOAUTHSTATUS | TCP_LINK_SOCKS_CROSSCONNECT | TCP_LINK_SOCKS_CONNSTATUS)) { icq_SocketSetHandler(plink->socket, ICQ_SOCKET_WRITE, NULL, NULL); icq_SocketSetHandler(plink->socket, ICQ_SOCKET_READ, (icq_SocketHandler)icq_TCPLinkOnConnect, plink); return; } len=sizeof(plink->socket_address); getsockname(plink->socket, (struct sockaddr *)&plink->socket_address, &len); icq_FmtLog(plink->icqlink, ICQ_LOG_MESSAGE, "connected to uin %d, socket=%d local address=%s:%d remote address=%s:%d\n", plink->remote_uin, plink->socket, inet_ntoa(*((struct in_addr *)(&plink->socket_address.sin_addr))), ntohs(plink->socket_address.sin_port), inet_ntoa(*((struct in_addr *)(&plink->remote_address.sin_addr))), ntohs(plink->remote_address.sin_port)); plink->mode&= ~TCP_LINK_MODE_CONNECTING; icq_SocketSetHandler(plink->socket, ICQ_SOCKET_READ, (icq_SocketHandler)icq_TCPLinkOnDataReceived, plink); icq_SocketSetHandler(plink->socket, ICQ_SOCKET_WRITE, NULL, NULL); /* socket is now connected, notify each request that connection * has been established and send pending data */ while(plink->send_queue->count>0) { icq_Packet *p=icq_ListDequeue(plink->send_queue); if(p->id) if(plink->icqlink->icq_RequestNotify) (*plink->icqlink->icq_RequestNotify)(plink->icqlink, p->id, ICQ_NOTIFY_CONNECTED, 0, 0); icq_TCPLinkSend(plink, p); } /* yeah this probably shouldn't be here. oh well :) */ if(plink->type==TCP_LINK_CHAT) { icq_ChatSessionSetStatus((icq_ChatSession *)plink->session, CHAT_STATUS_CONNECTED); icq_ChatSessionSetStatus((icq_ChatSession *)plink->session, CHAT_STATUS_WAIT_ALLINFO); } if(plink->type==TCP_LINK_FILE) { icq_FileSessionSetStatus((icq_FileSession *)plink->session, FILE_STATUS_CONNECTED); } } unsigned long icq_TCPLinkSendSeq(icq_TCPLink *plink, icq_Packet *p, unsigned long sequence) { /* append the next sequence number on the packet */ if (!sequence) sequence=plink->icqlink->d->icq_TCPSequence--; p->id=sequence; icq_PacketEnd(p); icq_PacketAppend32(p, sequence); /* if the link is currently connecting, queue the packets for * later, else send immediately */ if(plink->mode & TCP_LINK_MODE_CONNECTING) { icq_ListInsert(plink->send_queue, 0, p); if(plink->icqlink->icq_RequestNotify) (*plink->icqlink->icq_RequestNotify)(plink->icqlink, p->id, ICQ_NOTIFY_CONNECTING, 0, 0); } else { icq_PacketSend(p, plink->socket); if(p->id) if(plink->icqlink->icq_RequestNotify) (*plink->icqlink->icq_RequestNotify)(plink->icqlink, p->id, ICQ_NOTIFY_SENT, 0, 0); icq_PacketDelete(p); } return sequence; } void icq_TCPLinkSend(icq_TCPLink *plink, icq_Packet *p) { /* if the link is currently connecting, queue the packets for * later, else send immediately */ if(plink->mode & TCP_LINK_MODE_CONNECTING) { icq_ListInsert(plink->send_queue, 0, p); if(plink->icqlink->icq_RequestNotify) (*plink->icqlink->icq_RequestNotify)(plink->icqlink, p->id, ICQ_NOTIFY_CONNECTING, 0, 0); } else { icq_PacketSend(p, plink->socket); if(p->id) if(plink->icqlink->icq_RequestNotify) (*plink->icqlink->icq_RequestNotify)(plink->icqlink, p->id, ICQ_NOTIFY_SENT, 0, 0); icq_PacketDelete(p); } } void icq_TCPLinkProcessReceived(icq_TCPLink *plink) { icq_List *plist=plink->received_queue; while(plist->count>0) { icq_Packet *p=icq_ListDequeue(plist); if(plink->mode & TCP_LINK_MODE_HELLOWAIT) { icq_TCPProcessHello(p, plink); } else { switch (plink->type) { case TCP_LINK_MESSAGE: icq_TCPProcessPacket(p, plink); break; case TCP_LINK_CHAT: icq_TCPProcessChatPacket(p, plink); break; case TCP_LINK_FILE: icq_TCPProcessFilePacket(p, plink); break; } } icq_PacketDelete(p); } } int _icq_FindTCPLink(void *p, va_list data) { icq_TCPLink *plink=(icq_TCPLink *)p; unsigned long uin=va_arg(data, unsigned long); int type=va_arg(data, int); return ( (plink->remote_uin == uin ) && (plink->type == type) ); } icq_TCPLink *icq_FindTCPLink(icq_Link *icqlink, unsigned long uin, int type) { return icq_ListTraverse(icqlink->d->icq_TCPLinks, _icq_FindTCPLink, uin, type); }