view plugins/icq/icqevent.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: icqevent.c 1319 2000-12-19 10:08:29Z warmenhoven $
 *
 * $Log$
 * Revision 1.1  2000/12/19 10:08:29  warmenhoven
 * Yay, new icqlib
 *
 * Revision 1.2  2000/06/15 18:54:09  bills
 * added time attribute and handleEvent function pointer to icq_Event,
 * renamed icq_ChatEvent to icq_ChatRequestEvent, renamed icq_FileEvent to
 * icq_FileRequestEvent, added icq_URLEvent and related methods
 *
 * Revision 1.1  2000/06/15 15:27:39  bills
 * committed for safekeeping - this code will soon replace stdpackets.c and
 * greatly simplify tcphandle.c, as well as reducing code duplication in many
 * places.  it provides a much more flexible framework for managing events
 * and parsing and creating packets
 *
*/

#include <stdlib.h>

#include "icqevent.h"
#include "icqbyteorder.h"

#ifdef EVENT_DEBUG
#include <string.h>
#include <stdio.h>
#endif

#define new_event(x, y)   y * x = ( y * )malloc(sizeof(y))

/* generic Event - 'header' for each tcp packet */

void icq_EventInit(icq_Event *p, int type, int subtype, unsigned long uin, 
  int version)
{
  if (!p)
    return;

  p->uin=uin;
  p->version=version;
  p->type=type;
  p->subtype=subtype;
  p->direction=ICQ_EVENT_OUTGOING;
}

icq_Packet *icq_EventCreatePacket(icq_Event *pbase)
{
  icq_Packet *p=icq_PacketNew();

  /* create header for tcp packet */
  icq_PacketAppend32(p, pbase->uin);
  icq_PacketAppend16(p, pbase->version);
  icq_PacketAppend16(p, pbase->subtype);
  icq_PacketAppend16(p, 0x0000);
  icq_PacketAppend32(p, pbase->uin);
  icq_PacketAppend32(p, pbase->type);

  return p;
}

void icq_EventParsePacket(icq_Event *pevent, icq_Packet *p)
{
  /* parse header of tcp packet */
  icq_PacketBegin(p);
  (void)icq_PacketRead32(p);             /* uin */
  pevent->version=icq_PacketRead16(p);   /* max supported tcp version */
  pevent->subtype=icq_PacketRead16(p);   /* event subtype */
  (void)icq_PacketRead16(p);             /* 0x0000 */
  pevent->uin=icq_PacketRead32(p);       /* uin */
  pevent->type=icq_PacketRead16(p);      /* event type */
}

/* Message Event - extends generic Event */

icq_MessageEvent *icq_CreateMessageEvent(int subtype, unsigned long uin, 
  const char *message) 
{
  new_event(p, icq_MessageEvent);
  icq_Event *pbase=(icq_Event *)p;
  icq_MessageEventInit(p, ICQ_TCP_MSG_MSG, subtype, uin,
    ICQ_TCP_MSG_REAL, message);

  pbase->createPacket=icq_MessageCreatePacket;

#ifdef EVENT_DEBUG
  pbase->eventName=icq_MessageEventName;
  pbase->eventDump=icq_MessageEventDump;
#endif

  return p;
}

void icq_MessageEventInit(icq_MessageEvent *p, int type, int subtype, 
  unsigned long uin, int msgtype, const char *message)
{
  icq_EventInit((icq_Event *)p, type, subtype, uin, ICQ_TCP_VER);
  p->type=msgtype;
  p->message=(char *)message;
  p->status=0; /* FIXME */
}

icq_Packet *icq_MessageCreatePacket(icq_Event *pbase, icq_TCPLink *plink)
{
  icq_MessageEvent *pevent=(icq_MessageEvent *)pbase;

  /* create header */
  icq_Packet *p=icq_EventCreatePacket(pbase);

  /* append data specific to message event */
  icq_PacketAppendString(p, (char*)pevent->message);
  icq_PacketAppend32(p, plink->socket_address.sin_addr.s_addr);
  /* FIXME: should be RealIp */
  icq_PacketAppend32(p, htonl(plink->icqlink->icq_OurIP));
  icq_PacketAppend32(p, plink->socket_address.sin_port);
  icq_PacketAppend8(p, 0x04);
  icq_PacketAppend16(p, pevent->status);
  icq_PacketAppend16(p, pevent->type);

  return p;
}

void icq_MessageParsePacket(icq_Event *pbase, icq_Packet *p)
{
  icq_MessageEvent *pevent=(icq_MessageEvent *)pbase;

  /* parse message event data from packet */
  pevent->message=(char *)icq_PacketReadString(p);    /* message text */
  (void)icq_PacketRead32(p);                  /* remote ip */
  (void)icq_PacketRead32(p);                  /* remote real ip */
  (void)icq_PacketRead32(p);                  /* remote message port */
  (void)icq_PacketRead8(p);                   /* tcp flag */
  pevent->status=icq_PacketRead16(p);         /* remote user status */
  pevent->type=icq_PacketRead16(p);           /* message type */
}

#ifdef EVENT_DEBUG
const char *icq_MessageEventName(icq_Event *p)
{
  if (p->type==ICQ_EVENT_MESSAGE)
    return "message";
  else if (p->type==ICQ_EVENT_ACK)
    return "message ack";

  return "message cancel";
}

const char *icq_MessageEventDump(icq_Event *p)
{
  static char buf[255];
  icq_MessageEvent *pevent=(icq_MessageEvent *)p;

  sprintf(buf, ", type=%x, message=\"%10s...\", status=%x",
    pevent->type, pevent->message, pevent->status);

  return buf;
}
#endif

/* URL Event - extends message Event */

icq_URLEvent *icq_CreateURLEvent(int subtype, unsigned long uin,
  const char *message, const char *url)
{
  char *str=(char *)malloc(strlen(message)+strlen(url)+2);
  icq_Event *pbase;
  icq_URLEvent *p;

  strcpy((char*)str, message);
  *(str+strlen(message))=0xFE;
  strcpy((char*)(str+strlen(message)+1), url);

  /* TODO: make sure create message event copies message */
  pbase=(icq_Event *)icq_CreateMessageEvent(subtype, uin, str);
  p=(icq_URLEvent *)pbase;

  free(str);

  *(p->message+strlen(message))=0x00;
  p->url=p->message+strlen(message)+1;

  pbase->createPacket=icq_URLCreatePacket;

#ifdef EVENT_DEBUG
  pbase->eventName=icq_URLEventName;
  pbase->eventDump=icq_URLEventDump;
#endif

  return p;

}

icq_Packet *icq_URLCreatePacket(icq_Event *pbase, icq_TCPLink *plink)
{
  icq_URLEvent *pevent=(icq_URLEvent *)pbase;
  icq_Packet *p;

  /* hack message string to include url */
  *(pevent->message+strlen(pevent->message))=0xFE;

  /* create packet */
  p=icq_MessageCreatePacket(pbase, plink);

  /* hack message string to seperate url */
  *(pevent->message+strlen(pevent->message))=0x00;

  return p;
}

void icq_URLParsePacket(icq_Event *pbase, icq_Packet *p)
{
  char *pfe;
  icq_URLEvent *pevent=(icq_URLEvent *)pbase;

  /* TODO: make sure messageparsepacket allocates message string
   *       and add a delete event function */
  icq_MessageParsePacket(pbase, p);

  /* hack message string to seperate url */
  pfe=strchr(pevent->message, '\xFE');
  *pfe=0;
  
  /* set url */
  pevent->url=pfe+1;

}

#ifdef EVENT_DEBUG
const char *icq_URLEventName(icq_Event *p)
{
  if (p->type==ICQ_EVENT_MESSAGE)
    return "url";
  else if (p->type==ICQ_EVENT_ACK)
    return "url ack";

  return "url cancel";
}

const char *icq_URLEventDump(icq_Event *p)
{
  static char buf[255];
  icq_MessageEvent *pevent=(icq_MessageEvent *)p;

  sprintf(buf, ", type=%x, message=\"%10s...\", url=\"%10s...\" status=%x",
    pevent->type, pevent->message, pevent->url, pevent->status);

  return buf;
}
#endif


/* Chat Request Event - extends Message Event */

icq_ChatRequestEvent *icq_ChatRequestEventNew(int subtype,
  unsigned long uin, const char *message, int port)
{
  new_event(p, icq_ChatRequestEvent);
  icq_Event *pbase=(icq_Event *)p;
  icq_MessageEventInit((icq_MessageEvent *)p, ICQ_TCP_MSG_CHAT, subtype,
    uin, ICQ_TCP_MSG_REAL, message);
  p->port=port;

  pbase->createPacket=icq_ChatRequestCreatePacket;

#ifdef EVENT_DEBUG
  pbase->eventName=icq_ChatRequestEventName;
  pbase->eventDump=icq_ChatRequestEventDump;
#endif

  return p;
}

icq_Packet *icq_ChatRequestCreatePacket(icq_Event *pbase, 
  icq_TCPLink *plink)
{
  icq_ChatRequestEvent *pevent=(icq_ChatRequestEvent *)pbase;

  /* create header and message data */
  icq_Packet *p=icq_MessageCreatePacket(pbase, plink);

  /* append data specific to chat event */
  icq_PacketAppendString(p, 0);
  icq_PacketAppend32(p, htonl(pevent->port));
  icq_PacketAppend32(p, htoicql(pevent->port));  

  return p;
}

void icq_ChatParsePacket(icq_Event *pbase, icq_Packet *p)
{
  icq_ChatRequestEvent *pevent=(icq_ChatRequestEvent *)pbase;
  int port;

  /* parse header and message event data */
  icq_MessageParsePacket(pbase, p);

  /* parse chat event data */
  (void)icq_PacketReadString(p);      /* null string */
  port=icq_PacketRead32(p);           /* chat listen port, network order */
  (void)icq_PacketRead32(p);          /* chat listen port, intel order */

  pevent->port=ntohl(port);
}

#ifdef EVENT_DEBUG
const char *icq_ChatRequestEventName(icq_Event *p)
{
  if (p->type==ICQ_EVENT_MESSAGE)
    return "chat request";
  else if (p->type==ICQ_EVENT_ACK) {
    icq_MessageEvent *pevent=(icq_MessageEvent *)p;
    if (pevent->status==ICQ_TCP_STATUS_REFUSE)
      return "chat request refuse";
    else
      return "chat request ack";
  } else if (p->type==ICQ_EVENT_CANCEL) 
    return "chat request cancel";

  return "unknown chat request";
}

const char *icq_ChatRequestEventDump(icq_Event *p)
{
  static char buf[255];
  static char buf2[255];
  icq_ChatRequestEvent *pevent=(icq_ChatRequestEvent *)p;

  strcpy(buf, icq_MessageEventDump(p));
  sprintf(buf2, ", port=%d", pevent->port);
  strcat(buf, buf2);

  return buf;
}
#endif

/* File Request Event - builds on Message Event */

icq_FileRequestEvent *icq_FileRequestEventNew(int subtype,
  unsigned long uin,  const char *message, const char *filename,
  unsigned long filesize)
{
  new_event(p, icq_FileRequestEvent);
  icq_Event *pbase=(icq_Event *)p;
  icq_MessageEventInit((icq_MessageEvent *)p, ICQ_TCP_MSG_FILE, subtype,
    uin, ICQ_TCP_MSG_REAL, message);
  p->filename=filename;
  p->filesize=filesize;

  pbase->createPacket=icq_FileRequestCreatePacket;

#ifdef EVENT_DEBUG
  pbase->eventName=icq_FileRequestEventName;
  pbase->eventDump=icq_FileRequestEventDump;
#endif

  return p;
}

icq_Packet *icq_FileRequestCreatePacket(icq_Event *pbase, 
  icq_TCPLink *plink)
{
  icq_FileRequestEvent *pevent=(icq_FileRequestEvent *)pbase;

  /* create header and message data */
  icq_Packet *p=icq_MessageCreatePacket(pbase, plink);

  /* append file event data */
  icq_PacketAppend32(p, htonl(pevent->port));
  icq_PacketAppendString(p, pevent->filename);
  icq_PacketAppend32(p, pevent->filesize);
  icq_PacketAppend32(p, htoicql(pevent->port));

  return p;
}

void icq_FileParsePacket(icq_Event *pbase, icq_Packet *p)
{
  icq_FileRequestEvent *pevent=(icq_FileRequestEvent *)pbase;
  int port;

  /* parse header and message data */
  icq_MessageParsePacket(pbase, p);

  /* parse file event data */
  port=icq_PacketRead32(p);                 /* file listen port, network */
  pevent->filename=icq_PacketReadString(p); /* filename text */
  pevent->filesize=icq_PacketRead32(p);     /* total size */
  (void)icq_PacketRead32(p);                /* file listen port, intel */

  pevent->port=ntohl(port);
}

#ifdef EVENT_DEBUG
const char *icq_FileRequestEventName(icq_Event *p)
{
  if (p->type==ICQ_EVENT_MESSAGE)
    return "file request";
  else if (p->type==ICQ_EVENT_ACK) {
    icq_MessageEvent *pevent=(icq_MessageEvent *)p;
    if (pevent->status==ICQ_TCP_STATUS_REFUSE)
      return "file request refuse";
    else
      return "file request ack";
  } else if (p->type==ICQ_EVENT_CANCEL) 
    return "file request cancel";

  return "unknown file request";
}

const char *icq_FileRequestEventDump(icq_Event *p)
{
  static char buf[255];
  static char buf2[255];
  icq_FileRequestEvent *pevent=(icq_FileRequestEvent *)p;

  strcpy(buf, icq_MessageEventDump(p));
  sprintf(buf2, ", port=%d, filename=\"%s\", filesize=%ld", pevent->port,
    pevent->filename, pevent->filesize);
  strcat(buf, buf2);

  return buf;
}
#endif

/* main packet parser */

icq_Event *icq_ParsePacket(icq_Packet *p)
{
  /* FIXME */
  icq_Event *pevent=(icq_Event *)malloc(sizeof(icq_FileRequestEvent));
  pevent->direction=ICQ_EVENT_INCOMING;
  pevent->time=time(0);

  icq_EventParsePacket(pevent, p);

  switch(pevent->type) {

    case ICQ_TCP_MSG_MSG:
      icq_MessageParsePacket(pevent, p);
      break;
    case ICQ_TCP_MSG_URL:
      icq_URLParsePacket(pevent, p);
      break;
    case ICQ_TCP_MSG_CHAT:
      icq_ChatParsePacket(pevent, p);
      break;
    case ICQ_TCP_MSG_FILE:
      icq_FileParsePacket(pevent, p);
      break;
    default:
      /* FIXME: log */
      free(pevent);
      pevent=0;
      break;
  }

  /* FIXME: ensure no bytes are remaining */

  return pevent;
}

#ifdef EVENT_DEBUG
const char *icq_EventDump(icq_Event *pevent)
{
  static char buf[255];

  sprintf("%s event sent to uin %ld { %s }", (pevent->eventName)(pevent),
    pevent->uin, (pevent->eventDump)(pevent) );

  return buf;
}
#endif