diff src/protocols/icq/tcp.c @ 2086:424a40f12a6c

[gaim-migrate @ 2096] moving protocols from plugins/ to src/protocols. making it so that you can select which protocols are compiled statically. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Tue, 31 Jul 2001 01:00:39 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/protocols/icq/tcp.c	Tue Jul 31 01:00:39 2001 +0000
@@ -0,0 +1,465 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+/*
+ * $Id: tcp.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.
+ *
+ */
+
+/*
+ * Peer-to-peer ICQ protocol implementation
+ *
+ * Uses version 2 of the ICQ protocol
+ *
+ * Thanks to Douglas F. McLaughlin and many others for
+ * packet details (see tcp02.txt)
+ *
+ */
+
+#include <stdlib.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#ifdef _WIN32
+#include <winsock.h>
+#endif
+
+#include <sys/stat.h>
+
+#include "icqlib.h"
+
+#include "tcp.h"
+#include "stdpackets.h"
+#include "chatsession.h"
+#include "filesession.h"
+
+/**
+ Initializes structures necessary for TCP use.  Not required by user
+ programs.
+
+ \return true on error
+*/
+ 
+int icq_TCPInit(icq_Link *icqlink)
+{
+  icq_TCPLink *plink;
+
+  /* allocate lists */
+  icqlink->d->icq_TCPLinks=icq_ListNew();
+  icqlink->d->icq_ChatSessions=icq_ListNew();
+  icqlink->d->icq_FileSessions=icq_ListNew();
+
+  /* only the main listening socket gets created upon initialization -
+   * the other two are created when necessary */
+  plink=icq_TCPLinkNew(icqlink);
+  icq_TCPLinkListen(plink);
+  icqlink->icq_TCPSrvPort=ntohs(plink->socket_address.sin_port);
+
+  /* reset tcp sequence number */
+  icqlink->d->icq_TCPSequence=0xfffffffe;
+
+  return 0;
+}
+
+void icq_TCPDone(icq_Link *icqlink)
+{
+  /* close and deallocate all tcp links, this will also close any attached 
+   * file or chat sessions */
+  if (icqlink->d->icq_TCPLinks) {
+    icq_ListDelete(icqlink->d->icq_TCPLinks, icq_TCPLinkDelete);
+    icqlink->d->icq_TCPLinks = 0;
+  }
+  if (icqlink->d->icq_ChatSessions) {
+    icq_ListDelete(icqlink->d->icq_ChatSessions, icq_ChatSessionDelete);
+    icqlink->d->icq_ChatSessions = 0;
+  }
+  if (icqlink->d->icq_FileSessions) {
+    icq_ListDelete(icqlink->d->icq_FileSessions, icq_FileSessionDelete);
+    icqlink->d->icq_FileSessions = 0;
+  }
+}
+
+icq_TCPLink *icq_TCPCheckLink(icq_Link *icqlink, DWORD uin, int type)
+{
+  icq_TCPLink *plink=icq_FindTCPLink(icqlink, uin, type);
+
+  if(!plink)
+  {
+    plink=icq_TCPLinkNew(icqlink);
+    if(type==TCP_LINK_MESSAGE)
+      icq_TCPLinkConnect(plink, uin, 0);
+  }
+
+  return plink;
+}
+
+DWORD icq_TCPSendMessage(icq_Link *icqlink, DWORD uin, const char *message)
+{
+  icq_TCPLink *plink;
+  icq_Packet *p;
+  DWORD sequence;
+  char data[ICQ_MAX_MESSAGE_SIZE] ;
+  
+  strncpy(data,message,sizeof(data)) ;
+  data[sizeof(data)-1]='\0';
+  icq_RusConv("kw", data) ;
+
+  plink=icq_TCPCheckLink(icqlink, uin, TCP_LINK_MESSAGE);
+
+  /* create and send the message packet */
+  p=icq_TCPCreateMessagePacket(plink, data);
+  sequence=icq_TCPLinkSendSeq(plink, p, 0);
+
+#ifdef TCP_PACKET_TRACE
+  printf("message packet sent to uin %lu { sequence=%lx }\n", uin, p->id);
+#endif
+
+  return sequence;
+}
+
+DWORD icq_TCPSendURL(icq_Link *icqlink, DWORD uin, const char *message, const char *url)
+{
+  icq_TCPLink *plink;
+  icq_Packet *p;
+  DWORD sequence;
+  char data[ICQ_MAX_MESSAGE_SIZE];
+
+  plink=icq_TCPCheckLink(icqlink, uin, TCP_LINK_MESSAGE);
+  
+  strncpy(data, message, sizeof(data));
+  data[sizeof(data)-1] = '\0';
+  icq_RusConv("kw", data);
+
+  /* create and send the url packet */
+  p=icq_TCPCreateURLPacket(plink, data, url);
+  sequence=icq_TCPLinkSendSeq(plink, p, 0);
+
+#ifdef TCP_PACKET_TRACE
+  printf("url packet queued for uin %lu { sequence=%lx }\n", uin, p->id);
+#endif
+
+  return sequence;
+}
+
+DWORD icq_TCPSendAwayMessageReq(icq_Link *icqlink, DWORD uin, int status)
+{
+  icq_TCPLink *plink;
+  icq_Packet *p;
+  DWORD sequence;
+  WORD type;
+  
+  plink=icq_TCPCheckLink(icqlink, uin, TCP_LINK_MESSAGE);
+
+  /* create and send the message packet */
+  switch(status)
+  {
+    case STATUS_AWAY:
+      type=ICQ_TCP_MSG_READAWAY;
+      break;
+    case STATUS_DND:
+      type=ICQ_TCP_MSG_READDND;
+      break;
+    case STATUS_NA:
+      type=ICQ_TCP_MSG_READNA;
+      break;
+    case STATUS_OCCUPIED:
+      type=ICQ_TCP_MSG_READOCCUPIED;
+      break;
+    case STATUS_FREE_CHAT:
+      type=ICQ_TCP_MSG_READFFC;
+      break;
+    default:
+      type=ICQ_TCP_MSG_READAWAY;
+      break;
+  }
+  p=icq_TCPCreateAwayReqPacket(plink, type);
+  sequence=icq_TCPLinkSendSeq(plink, p, 0);
+
+#ifdef TCP_PACKET_TRACE
+  printf("away msg request packet sent to uin %lu { sequence=%lx }\n", uin, p->id);
+#endif
+
+  return sequence;
+}
+
+DWORD icq_SendChatRequest(icq_Link *icqlink, DWORD uin, const char *message)
+{
+  icq_TCPLink *plink;
+  icq_Packet *p;
+  DWORD sequence;
+  char data[ICQ_MAX_MESSAGE_SIZE];
+
+  plink=icq_TCPCheckLink(icqlink, uin, TCP_LINK_MESSAGE);
+  
+  strncpy(data, message, sizeof(data));
+  data[sizeof(data)-1] = '\0';
+  icq_RusConv("kw", data);
+
+  /* create and send the url packet */
+  p=icq_TCPCreateChatReqPacket(plink, data);
+  sequence=icq_TCPLinkSendSeq(plink, p, 0);
+
+#ifdef TCP_PACKET_TRACE
+  printf("chat req packet sent to uin %lu { sequence=%lx }\n", uin, p->id);
+#endif
+
+  return sequence;
+}
+
+unsigned long icq_SendFileRequest(icq_Link *icqlink, unsigned long uin,
+  const char *message, char **files)
+{
+  icq_TCPLink *plink;
+  icq_FileSession *pfile;
+  icq_Packet *p;
+  unsigned long sequence;
+  char filename[64];
+  char data[ICQ_MAX_MESSAGE_SIZE];
+  char **filesiterator;
+  char **pfilesiterator;
+
+  plink=icq_TCPCheckLink(icqlink, uin, TCP_LINK_MESSAGE);
+
+  /* create the file session, this will be linked to the incoming icq_TCPLink
+   * in icq_HandleFileAck */ 
+  pfile=icq_FileSessionNew(icqlink);
+  pfile->remote_uin=uin;
+  pfile->files=files;
+  pfile->direction=FILE_STATUS_SENDING;
+
+  /* count the number and size of the files */
+  pfile->total_files=0;
+  filesiterator = files;
+  while(*filesiterator) {
+#ifdef _WIN32
+    struct _stat file_status;
+    if(_stat(*filesiterator, &file_status)==0) {
+#else
+    struct stat file_status;
+    if(stat(*filesiterator, &file_status)==0) {
+#endif
+      pfile->total_files++;
+      pfile->total_bytes+=file_status.st_size;
+    }
+    filesiterator++;
+  }
+
+  pfile->files=(char **)malloc(sizeof(char *)*(pfile->total_files +1));
+  filesiterator = files;
+  pfilesiterator = pfile->files;
+  while (*filesiterator) {
+    *pfilesiterator=(char *)malloc(strlen(*filesiterator)+1);
+    strcpy(*pfilesiterator,*filesiterator);
+    filesiterator++;
+    pfilesiterator++;
+  }
+  *pfilesiterator = NULL;
+
+  strncpy(filename, *(pfile->files), 64);
+
+  strncpy(data, message, sizeof(data));
+  data[sizeof(data)-1]='\0';
+  icq_RusConv("kw", data);  
+
+  /* create and send the file req packet */
+  p=icq_TCPCreateFileReqPacket(plink, (char *)data, filename, 
+    pfile->total_bytes);
+  sequence=icq_TCPLinkSendSeq(plink, p, 0);
+  pfile->id=sequence;
+
+#ifdef TCP_PACKET_TRACE
+  printf("file req packet sent to uin %lu { sequence=%lx }\n", uin, p->id);
+#endif
+
+  return sequence;
+}            
+
+void icq_AcceptChatRequest(icq_Link *icqlink, DWORD uin, unsigned long sequence)
+{
+  icq_TCPLink *pmessage, *plisten;
+  icq_ChatSession *pchat;
+  icq_Packet *p;
+
+  pmessage=icq_TCPCheckLink(icqlink, uin, TCP_LINK_MESSAGE);
+
+  /* create the chat listening socket if necessary */
+  if(!(plisten=icq_FindTCPLink(icqlink, 0, TCP_LINK_CHAT)))
+  {
+    plisten=icq_TCPLinkNew(icqlink);
+    plisten->type=TCP_LINK_CHAT;
+    icq_TCPLinkListen(plisten);
+  }
+
+  /* create the chat session, this will be linked to the incoming icq_TCPLink
+   * in TCPProcessHello */ 
+  pchat=icq_ChatSessionNew(icqlink);
+  pchat->id=sequence;
+  pchat->remote_uin=uin;
+
+  /* create and send the ack packet */
+  p=icq_TCPCreateChatReqAck(pmessage,
+    ntohs(plisten->socket_address.sin_port));
+  (void)icq_TCPLinkSendSeq(pmessage, p, sequence);
+
+#ifdef TCP_PACKET_TRACE
+  printf("chat req ack sent to uin %lu { sequence=%lx }\n", uin, sequence);
+#endif
+}
+
+void icq_TCPSendChatData(icq_Link *icqlink, DWORD uin, const char *data)
+{
+  icq_TCPLink *plink=icq_FindTCPLink(icqlink, uin, TCP_LINK_CHAT);
+  char data1[ICQ_MAX_MESSAGE_SIZE];
+  int data1_len;
+
+  if(!plink)
+    return;  
+
+  strncpy(data1,data,sizeof(data1)) ;
+  data1[sizeof(data1)-1] = '\0';
+  data1_len = strlen(data);
+  icq_ChatRusConv_n("kw", data1, data1_len);
+
+  send(plink->socket, data1, data1_len, 0);
+}
+
+void icq_TCPSendChatData_n(icq_Link *icqlink, DWORD uin, const char *data, int len)
+{
+  icq_TCPLink *plink=icq_FindTCPLink(icqlink, uin, TCP_LINK_CHAT);
+  char *data1;
+
+  if(!plink)
+    return;
+
+  data1 = (char *)malloc(len);
+  memcpy(data1, data, len);
+  icq_ChatRusConv_n("kw", data1, len);  
+
+  send(plink->socket, data1, len, 0);
+}
+
+icq_FileSession *icq_AcceptFileRequest(icq_Link *icqlink, DWORD uin,
+  unsigned long sequence)
+{
+  icq_TCPLink *pmessage, *plisten;
+  icq_FileSession *pfile;
+  icq_Packet *p;
+
+  pmessage=icq_TCPCheckLink(icqlink, uin, TCP_LINK_MESSAGE);
+
+  /* create the file listening socket if necessary */
+  if(!(plisten=icq_FindTCPLink(icqlink, 0, TCP_LINK_FILE)))
+  {
+    plisten=icq_TCPLinkNew(icqlink);
+    plisten->type=TCP_LINK_FILE;
+    icq_TCPLinkListen(plisten);
+  }
+
+  /* create the file session, this will be linked to the incoming icq_TCPLink
+   * in TCPProcessHello */ 
+  pfile=icq_FileSessionNew(icqlink);
+  pfile->id=sequence;
+  pfile->remote_uin=uin;
+  pfile->direction=FILE_STATUS_RECEIVING;
+  pfile->tcplink=plisten;
+  icq_FileSessionSetStatus(pfile, FILE_STATUS_LISTENING);
+
+  /* create and send the ack packet */
+  p=icq_TCPCreateFileReqAck(pmessage, 
+    ntohs(plisten->socket_address.sin_port));
+  (void)icq_TCPLinkSendSeq(pmessage, p, sequence);
+
+#ifdef TCP_PACKET_TRACE
+  printf("file req ack sent to uin %lu { sequence=%lx }\n", uin, sequence);
+#endif
+
+  return pfile;
+}
+
+void icq_RefuseFileRequest(icq_Link *icqlink, DWORD uin, 
+  unsigned long sequence, const char *reason)
+{
+  icq_TCPLink *pmessage=icq_TCPCheckLink(icqlink, uin, TCP_LINK_MESSAGE);
+  icq_Packet *p;
+
+  /* create and send the refuse packet */
+  p=icq_TCPCreateFileReqRefuse(pmessage,
+    ntohs(pmessage->socket_address.sin_port), reason);
+  (void)icq_TCPLinkSendSeq(pmessage, p, sequence);
+
+#ifdef TCP_PACKET_TRACE
+  printf("file req refuse sent to uin %lu { sequence=%lx, reason=\"%s\" }\n",
+    uin, sequence, reason);
+#endif
+}
+
+void icq_CancelFileRequest(icq_Link *icqlink, DWORD uin, unsigned long sequence)
+{
+  icq_TCPLink *pmessage=icq_TCPCheckLink(icqlink, uin, TCP_LINK_MESSAGE);
+  icq_FileSession *psession=icq_FindFileSession(icqlink, uin, sequence);
+  icq_Packet *p;
+
+  if (psession)
+    icq_FileSessionClose(psession);
+
+  /* create and send the cancel packet */
+  p=icq_TCPCreateFileReqCancel(pmessage,
+    ntohs(pmessage->socket_address.sin_port));
+  (void)icq_TCPLinkSendSeq(pmessage, p, sequence);
+#ifdef TCP_PACKET_TRACE
+  printf("file req cancel sent to uin %lu { sequence=%lx }\n", uin, sequence);
+#endif
+}
+
+void icq_RefuseChatRequest(icq_Link *icqlink, DWORD uin, 
+  unsigned long sequence, const char *reason)
+{
+  icq_TCPLink *pmessage=icq_TCPCheckLink(icqlink, uin, TCP_LINK_MESSAGE);
+  icq_Packet *p;
+
+  /* create and send the refuse packet */
+  p=icq_TCPCreateChatReqRefuse(pmessage,
+    ntohs(pmessage->socket_address.sin_port), reason);
+  (void)icq_TCPLinkSendSeq(pmessage, p, sequence);
+
+#ifdef TCP_PACKET_TRACE
+  printf("chat req refuse sent to uin %lu { sequence=%lx, reason=\"%s\" }\n",
+    uin, sequence, reason);
+#endif
+}
+
+void icq_CancelChatRequest(icq_Link *icqlink, DWORD uin, unsigned long sequence)
+{
+  icq_TCPLink *pmessage=icq_TCPCheckLink(icqlink, uin, TCP_LINK_MESSAGE);
+  icq_ChatSession *psession=icq_FindChatSession(icqlink, uin);
+  icq_Packet *p;
+
+  if (psession)
+    icq_ChatSessionClose(psession);
+
+  /* create and send the cancel packet */
+  p=icq_TCPCreateChatReqCancel(pmessage,
+    ntohs(pmessage->socket_address.sin_port));
+  (void)icq_TCPLinkSendSeq(pmessage, p, sequence);
+
+#ifdef TCP_PACKET_TRACE
+  printf("chat req cancel sent to uin %lu { sequence=%lx }\n", uin, sequence);
+#endif
+}