Thu, 02 Oct 2003 01:58:26 +0000
[gaim-migrate @ 7683]
fix a big ugly memleak on jabber account signoff, fix the img display in vcards until the gtk code can be talked into understanding proper XHTML, and a few misc other things I felt like getting out of my tree.
| 2086 | 1 | /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
| 2 | ||
| 3 | /* | |
|
2496
55a3120eb8e6
[gaim-migrate @ 2509]
Eric Warmenhoven <warmenhoven@yahoo.com>
parents:
2086
diff
changeset
|
4 | * $Id: icqevent.c 2509 2001-10-13 00:06:18Z warmenhoven $ |
| 2086 | 5 | * |
| 6 | * Copyright (C) 1998-2001, Denis V. Dmitrienko <denis@null.net> and | |
| 7 | * Bill Soudan <soudan@kde.org> | |
| 8 | * | |
| 9 | * This program is free software; you can redistribute it and/or modify | |
| 10 | * it under the terms of the GNU General Public License as published by | |
| 11 | * the Free Software Foundation; either version 2 of the License, or | |
| 12 | * (at your option) any later version. | |
| 13 | * | |
| 14 | * This program is distributed in the hope that it will be useful, | |
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 17 | * GNU General Public License for more details. | |
| 18 | * | |
| 19 | * You should have received a copy of the GNU General Public License | |
| 20 | * along with this program; if not, write to the Free Software | |
| 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
| 22 | * | |
| 23 | */ | |
| 24 | ||
| 25 | #include <stdlib.h> | |
| 26 | ||
| 27 | #include "icqlib.h" /* for icqbyteorder.h ?! */ | |
| 28 | #include "icqbyteorder.h" | |
| 29 | #include "icqevent.h" | |
| 30 | ||
| 31 | #ifdef EVENT_DEBUG | |
| 32 | #include <string.h> | |
| 33 | #include <stdio.h> | |
| 34 | #endif | |
| 35 | ||
| 36 | #define new_event(x, y) y * x = ( y * )malloc(sizeof(y)) | |
| 37 | ||
| 38 | /* generic Event - 'header' for each tcp packet */ | |
| 39 | ||
| 40 | void icq_EventInit(icq_Event *p, int type, int subtype, unsigned long uin, | |
| 41 | int version) | |
| 42 | { | |
| 43 | if (!p) | |
| 44 | return; | |
| 45 | ||
| 46 | p->uin=uin; | |
| 47 | p->version=version; | |
| 48 | p->type=type; | |
| 49 | p->subtype=subtype; | |
| 50 | p->direction=ICQ_EVENT_OUTGOING; | |
| 51 | } | |
| 52 | ||
| 53 | icq_Packet *icq_EventCreatePacket(icq_Event *pbase) | |
| 54 | { | |
| 55 | icq_Packet *p=icq_PacketNew(); | |
| 56 | ||
| 57 | /* create header for tcp packet */ | |
| 58 | icq_PacketAppend32(p, pbase->uin); | |
| 59 | icq_PacketAppend16(p, pbase->version); | |
| 60 | icq_PacketAppend16(p, pbase->subtype); | |
| 61 | icq_PacketAppend16(p, 0x0000); | |
| 62 | icq_PacketAppend32(p, pbase->uin); | |
| 63 | icq_PacketAppend32(p, pbase->type); | |
| 64 | ||
| 65 | return p; | |
| 66 | } | |
| 67 | ||
| 68 | void icq_EventParsePacket(icq_Event *pevent, icq_Packet *p) | |
| 69 | { | |
| 70 | /* parse header of tcp packet */ | |
| 71 | icq_PacketBegin(p); | |
| 72 | (void)icq_PacketRead32(p); /* uin */ | |
| 73 | pevent->version=icq_PacketRead16(p); /* max supported tcp version */ | |
| 74 | pevent->subtype=icq_PacketRead16(p); /* event subtype */ | |
| 75 | (void)icq_PacketRead16(p); /* 0x0000 */ | |
| 76 | pevent->uin=icq_PacketRead32(p); /* uin */ | |
| 77 | pevent->type=icq_PacketRead16(p); /* event type */ | |
| 78 | } | |
| 79 | ||
| 80 | /* Message Event - extends generic Event */ | |
| 81 | ||
| 82 | icq_MessageEvent *icq_CreateMessageEvent(int subtype, unsigned long uin, | |
| 83 | const char *message) | |
| 84 | { | |
| 85 | new_event(p, icq_MessageEvent); | |
| 86 | icq_Event *pbase=(icq_Event *)p; | |
| 87 | icq_MessageEventInit(p, ICQ_TCP_MSG_MSG, subtype, uin, | |
| 88 | ICQ_TCP_MSG_REAL, message); | |
| 89 | ||
| 90 | pbase->createPacket=icq_MessageCreatePacket; | |
| 91 | ||
| 92 | #ifdef EVENT_DEBUG | |
| 93 | pbase->eventName=icq_MessageEventName; | |
| 94 | pbase->eventDump=icq_MessageEventDump; | |
| 95 | #endif | |
| 96 | ||
| 97 | return p; | |
| 98 | } | |
| 99 | ||
| 100 | void icq_MessageEventInit(icq_MessageEvent *p, int type, int subtype, | |
| 101 | unsigned long uin, int msgtype, const char *message) | |
| 102 | { | |
| 103 | icq_EventInit((icq_Event *)p, type, subtype, uin, ICQ_TCP_VER); | |
| 104 | p->type=msgtype; | |
| 105 | p->message=(char *)message; | |
| 106 | p->status=0; /* FIXME */ | |
| 107 | } | |
| 108 | ||
| 109 | icq_Packet *icq_MessageCreatePacket(icq_Event *pbase, icq_TCPLink *plink) | |
| 110 | { | |
| 111 | icq_MessageEvent *pevent=(icq_MessageEvent *)pbase; | |
| 112 | ||
| 113 | /* create header */ | |
| 114 | icq_Packet *p=icq_EventCreatePacket(pbase); | |
| 115 | ||
| 116 | /* append data specific to message event */ | |
| 117 | icq_PacketAppendString(p, (char*)pevent->message); | |
| 118 | icq_PacketAppend32(p, plink->socket_address.sin_addr.s_addr); | |
| 119 | /* FIXME: should be RealIp */ | |
| 120 | icq_PacketAppend32(p, htonl(plink->icqlink->icq_OurIP)); | |
| 121 | icq_PacketAppend32(p, plink->socket_address.sin_port); | |
| 122 | icq_PacketAppend8(p, 0x04); | |
| 123 | icq_PacketAppend16(p, pevent->status); | |
| 124 | icq_PacketAppend16(p, pevent->type); | |
| 125 | ||
| 126 | return p; | |
| 127 | } | |
| 128 | ||
| 129 | void icq_MessageParsePacket(icq_Event *pbase, icq_Packet *p) | |
| 130 | { | |
| 131 | icq_MessageEvent *pevent=(icq_MessageEvent *)pbase; | |
| 132 | ||
| 133 | /* parse message event data from packet */ | |
| 134 | pevent->message=(char *)icq_PacketReadString(p); /* message text */ | |
| 135 | (void)icq_PacketRead32(p); /* remote ip */ | |
| 136 | (void)icq_PacketRead32(p); /* remote real ip */ | |
| 137 | (void)icq_PacketRead32(p); /* remote message port */ | |
| 138 | (void)icq_PacketRead8(p); /* tcp flag */ | |
| 139 | pevent->status=icq_PacketRead16(p); /* remote user status */ | |
| 140 | pevent->type=icq_PacketRead16(p); /* message type */ | |
| 141 | } | |
| 142 | ||
| 143 | #ifdef EVENT_DEBUG | |
| 144 | const char *icq_MessageEventName(icq_Event *p) | |
| 145 | { | |
| 146 | if (p->type==ICQ_EVENT_MESSAGE) | |
| 147 | return "message"; | |
| 148 | else if (p->type==ICQ_EVENT_ACK) | |
| 149 | return "message ack"; | |
| 150 | ||
| 151 | return "message cancel"; | |
| 152 | } | |
| 153 | ||
| 154 | const char *icq_MessageEventDump(icq_Event *p) | |
| 155 | { | |
| 156 | static char buf[255]; | |
| 157 | icq_MessageEvent *pevent=(icq_MessageEvent *)p; | |
| 158 | ||
| 159 | sprintf(buf, ", type=%x, message=\"%10s...\", status=%x", | |
| 160 | pevent->type, pevent->message, pevent->status); | |
| 161 | ||
| 162 | return buf; | |
| 163 | } | |
| 164 | #endif | |
| 165 | ||
| 166 | /* URL Event - extends message Event */ | |
| 167 | ||
| 168 | icq_URLEvent *icq_CreateURLEvent(int subtype, unsigned long uin, | |
| 169 | const char *message, const char *url) | |
| 170 | { | |
| 171 | char *str=(char *)malloc(strlen(message)+strlen(url)+2); | |
| 172 | icq_Event *pbase; | |
| 173 | icq_URLEvent *p; | |
| 174 | ||
| 175 | strcpy((char*)str, message); | |
| 176 | *(str+strlen(message))=0xFE; | |
| 177 | strcpy((char*)(str+strlen(message)+1), url); | |
| 178 | ||
| 179 | /* TODO: make sure create message event copies message */ | |
| 180 | pbase=(icq_Event *)icq_CreateMessageEvent(subtype, uin, str); | |
| 181 | p=(icq_URLEvent *)pbase; | |
| 182 | ||
| 183 | free(str); | |
| 184 | ||
| 185 | *(p->message+strlen(message))=0x00; | |
| 186 | p->url=p->message+strlen(message)+1; | |
| 187 | ||
| 188 | pbase->createPacket=icq_URLCreatePacket; | |
| 189 | ||
| 190 | #ifdef EVENT_DEBUG | |
| 191 | pbase->eventName=icq_URLEventName; | |
| 192 | pbase->eventDump=icq_URLEventDump; | |
| 193 | #endif | |
| 194 | ||
| 195 | return p; | |
| 196 | ||
| 197 | } | |
| 198 | ||
| 199 | icq_Packet *icq_URLCreatePacket(icq_Event *pbase, icq_TCPLink *plink) | |
| 200 | { | |
| 201 | icq_URLEvent *pevent=(icq_URLEvent *)pbase; | |
| 202 | icq_Packet *p; | |
| 203 | ||
| 204 | /* hack message string to include url */ | |
| 205 | *(pevent->message+strlen(pevent->message))=0xFE; | |
| 206 | ||
| 207 | /* create packet */ | |
| 208 | p=icq_MessageCreatePacket(pbase, plink); | |
| 209 | ||
| 210 | /* hack message string to seperate url */ | |
| 211 | *(pevent->message+strlen(pevent->message))=0x00; | |
| 212 | ||
| 213 | return p; | |
| 214 | } | |
| 215 | ||
| 216 | void icq_URLParsePacket(icq_Event *pbase, icq_Packet *p) | |
| 217 | { | |
| 218 | char *pfe; | |
| 219 | icq_URLEvent *pevent=(icq_URLEvent *)pbase; | |
| 220 | ||
| 221 | /* TODO: make sure messageparsepacket allocates message string | |
| 222 | * and add a delete event function */ | |
| 223 | icq_MessageParsePacket(pbase, p); | |
| 224 | ||
| 225 | /* hack message string to seperate url */ | |
| 226 | pfe=strchr(pevent->message, '\xFE'); | |
| 227 | *pfe=0; | |
| 228 | ||
| 229 | /* set url */ | |
| 230 | pevent->url=pfe+1; | |
| 231 | ||
| 232 | } | |
| 233 | ||
| 234 | #ifdef EVENT_DEBUG | |
| 235 | const char *icq_URLEventName(icq_Event *p) | |
| 236 | { | |
| 237 | if (p->type==ICQ_EVENT_MESSAGE) | |
| 238 | return "url"; | |
| 239 | else if (p->type==ICQ_EVENT_ACK) | |
| 240 | return "url ack"; | |
| 241 | ||
| 242 | return "url cancel"; | |
| 243 | } | |
| 244 | ||
| 245 | const char *icq_URLEventDump(icq_Event *p) | |
| 246 | { | |
| 247 | static char buf[255]; | |
| 248 | icq_MessageEvent *pevent=(icq_MessageEvent *)p; | |
| 249 | ||
| 250 | sprintf(buf, ", type=%x, message=\"%10s...\", url=\"%10s...\" status=%x", | |
| 251 | pevent->type, pevent->message, pevent->url, pevent->status); | |
| 252 | ||
| 253 | return buf; | |
| 254 | } | |
| 255 | #endif | |
| 256 | ||
| 257 | ||
| 258 | /* Chat Request Event - extends Message Event */ | |
| 259 | ||
| 260 | icq_ChatRequestEvent *icq_ChatRequestEventNew(int subtype, | |
| 261 | unsigned long uin, const char *message, int port) | |
| 262 | { | |
| 263 | new_event(p, icq_ChatRequestEvent); | |
| 264 | icq_Event *pbase=(icq_Event *)p; | |
| 265 | icq_MessageEventInit((icq_MessageEvent *)p, ICQ_TCP_MSG_CHAT, subtype, | |
| 266 | uin, ICQ_TCP_MSG_REAL, message); | |
| 267 | p->port=port; | |
| 268 | ||
| 269 | pbase->createPacket=icq_ChatRequestCreatePacket; | |
| 270 | ||
| 271 | #ifdef EVENT_DEBUG | |
| 272 | pbase->eventName=icq_ChatRequestEventName; | |
| 273 | pbase->eventDump=icq_ChatRequestEventDump; | |
| 274 | #endif | |
| 275 | ||
| 276 | return p; | |
| 277 | } | |
| 278 | ||
| 279 | icq_Packet *icq_ChatRequestCreatePacket(icq_Event *pbase, | |
| 280 | icq_TCPLink *plink) | |
| 281 | { | |
| 282 | icq_ChatRequestEvent *pevent=(icq_ChatRequestEvent *)pbase; | |
| 283 | ||
| 284 | /* create header and message data */ | |
| 285 | icq_Packet *p=icq_MessageCreatePacket(pbase, plink); | |
| 286 | ||
| 287 | /* append data specific to chat event */ | |
| 288 | icq_PacketAppendString(p, 0); | |
| 289 | icq_PacketAppend32(p, htonl(pevent->port)); | |
| 290 | icq_PacketAppend32(p, htoicql(pevent->port)); | |
| 291 | ||
| 292 | return p; | |
| 293 | } | |
| 294 | ||
| 295 | void icq_ChatParsePacket(icq_Event *pbase, icq_Packet *p) | |
| 296 | { | |
| 297 | icq_ChatRequestEvent *pevent=(icq_ChatRequestEvent *)pbase; | |
| 298 | int port; | |
| 299 | ||
| 300 | /* parse header and message event data */ | |
| 301 | icq_MessageParsePacket(pbase, p); | |
| 302 | ||
| 303 | /* parse chat event data */ | |
| 304 | (void)icq_PacketReadString(p); /* null string */ | |
| 305 | port=icq_PacketRead32(p); /* chat listen port, network order */ | |
| 306 | (void)icq_PacketRead32(p); /* chat listen port, intel order */ | |
| 307 | ||
| 308 | pevent->port=ntohl(port); | |
| 309 | } | |
| 310 | ||
| 311 | #ifdef EVENT_DEBUG | |
| 312 | const char *icq_ChatRequestEventName(icq_Event *p) | |
| 313 | { | |
| 314 | if (p->type==ICQ_EVENT_MESSAGE) | |
| 315 | return "chat request"; | |
| 316 | else if (p->type==ICQ_EVENT_ACK) { | |
| 317 | icq_MessageEvent *pevent=(icq_MessageEvent *)p; | |
| 318 | if (pevent->status==ICQ_TCP_STATUS_REFUSE) | |
| 319 | return "chat request refuse"; | |
| 320 | else | |
| 321 | return "chat request ack"; | |
| 322 | } else if (p->type==ICQ_EVENT_CANCEL) | |
| 323 | return "chat request cancel"; | |
| 324 | ||
| 325 | return "unknown chat request"; | |
| 326 | } | |
| 327 | ||
| 328 | const char *icq_ChatRequestEventDump(icq_Event *p) | |
| 329 | { | |
| 330 | static char buf[255]; | |
| 331 | static char buf2[255]; | |
| 332 | icq_ChatRequestEvent *pevent=(icq_ChatRequestEvent *)p; | |
| 333 | ||
| 334 | strcpy(buf, icq_MessageEventDump(p)); | |
| 335 | sprintf(buf2, ", port=%d", pevent->port); | |
| 336 | strcat(buf, buf2); | |
| 337 | ||
| 338 | return buf; | |
| 339 | } | |
| 340 | #endif | |
| 341 | ||
| 342 | /* File Request Event - builds on Message Event */ | |
| 343 | ||
| 344 | icq_FileRequestEvent *icq_FileRequestEventNew(int subtype, | |
| 345 | unsigned long uin, const char *message, const char *filename, | |
| 346 | unsigned long filesize) | |
| 347 | { | |
| 348 | new_event(p, icq_FileRequestEvent); | |
| 349 | icq_Event *pbase=(icq_Event *)p; | |
| 350 | icq_MessageEventInit((icq_MessageEvent *)p, ICQ_TCP_MSG_FILE, subtype, | |
| 351 | uin, ICQ_TCP_MSG_REAL, message); | |
| 352 | p->filename=filename; | |
| 353 | p->filesize=filesize; | |
| 354 | ||
| 355 | pbase->createPacket=icq_FileRequestCreatePacket; | |
| 356 | ||
| 357 | #ifdef EVENT_DEBUG | |
| 358 | pbase->eventName=icq_FileRequestEventName; | |
| 359 | pbase->eventDump=icq_FileRequestEventDump; | |
| 360 | #endif | |
| 361 | ||
| 362 | return p; | |
| 363 | } | |
| 364 | ||
| 365 | icq_Packet *icq_FileRequestCreatePacket(icq_Event *pbase, | |
| 366 | icq_TCPLink *plink) | |
| 367 | { | |
| 368 | icq_FileRequestEvent *pevent=(icq_FileRequestEvent *)pbase; | |
| 369 | ||
| 370 | /* create header and message data */ | |
| 371 | icq_Packet *p=icq_MessageCreatePacket(pbase, plink); | |
| 372 | ||
| 373 | /* append file event data */ | |
| 374 | icq_PacketAppend32(p, htonl(pevent->port)); | |
| 375 | icq_PacketAppendString(p, pevent->filename); | |
| 376 | icq_PacketAppend32(p, pevent->filesize); | |
| 377 | icq_PacketAppend32(p, htoicql(pevent->port)); | |
| 378 | ||
| 379 | return p; | |
| 380 | } | |
| 381 | ||
| 382 | void icq_FileParsePacket(icq_Event *pbase, icq_Packet *p) | |
| 383 | { | |
| 384 | icq_FileRequestEvent *pevent=(icq_FileRequestEvent *)pbase; | |
| 385 | ||
| 386 | /* parse header and message data */ | |
| 387 | icq_MessageParsePacket(pbase, p); | |
| 388 | ||
| 389 | /* parse file event data */ | |
| 390 | pevent->port=ntohl(icq_PacketRead32(p)); /* file listen port, network */ | |
| 391 | pevent->filename=icq_PacketReadString(p); /* filename text */ | |
| 392 | pevent->filesize=icq_PacketRead32(p); /* total size */ | |
| 393 | (void)icq_PacketRead32(p); /* file listen port, intel */ | |
| 394 | } | |
| 395 | ||
| 396 | #ifdef EVENT_DEBUG | |
| 397 | const char *icq_FileRequestEventName(icq_Event *p) | |
| 398 | { | |
| 399 | if (p->type==ICQ_EVENT_MESSAGE) | |
| 400 | return "file request"; | |
| 401 | else if (p->type==ICQ_EVENT_ACK) { | |
| 402 | icq_MessageEvent *pevent=(icq_MessageEvent *)p; | |
| 403 | if (pevent->status==ICQ_TCP_STATUS_REFUSE) | |
| 404 | return "file request refuse"; | |
| 405 | else | |
| 406 | return "file request ack"; | |
| 407 | } else if (p->type==ICQ_EVENT_CANCEL) | |
| 408 | return "file request cancel"; | |
| 409 | ||
| 410 | return "unknown file request"; | |
| 411 | } | |
| 412 | ||
| 413 | const char *icq_FileRequestEventDump(icq_Event *p) | |
| 414 | { | |
| 415 | static char buf[255]; | |
| 416 | static char buf2[255]; | |
| 417 | icq_FileRequestEvent *pevent=(icq_FileRequestEvent *)p; | |
| 418 | ||
| 419 | strcpy(buf, icq_MessageEventDump(p)); | |
| 420 | sprintf(buf2, ", port=%d, filename=\"%s\", filesize=%ld", pevent->port, | |
| 421 | pevent->filename, pevent->filesize); | |
| 422 | strcat(buf, buf2); | |
| 423 | ||
| 424 | return buf; | |
| 425 | } | |
| 426 | #endif | |
| 427 | ||
| 428 | /* main packet parser */ | |
| 429 | ||
| 430 | icq_Event *icq_ParsePacket(icq_Packet *p) | |
| 431 | { | |
| 432 | /* FIXME */ | |
| 433 | icq_Event *pevent=(icq_Event *)malloc(sizeof(icq_FileRequestEvent)); | |
| 434 | pevent->direction=ICQ_EVENT_INCOMING; | |
| 435 | pevent->time=time(0); | |
| 436 | ||
| 437 | icq_EventParsePacket(pevent, p); | |
| 438 | ||
| 439 | switch(pevent->type) { | |
| 440 | ||
| 441 | case ICQ_TCP_MSG_MSG: | |
| 442 | icq_MessageParsePacket(pevent, p); | |
| 443 | break; | |
| 444 | case ICQ_TCP_MSG_URL: | |
| 445 | icq_URLParsePacket(pevent, p); | |
| 446 | break; | |
| 447 | case ICQ_TCP_MSG_CHAT: | |
| 448 | icq_ChatParsePacket(pevent, p); | |
| 449 | break; | |
| 450 | case ICQ_TCP_MSG_FILE: | |
| 451 | icq_FileParsePacket(pevent, p); | |
| 452 | break; | |
| 453 | default: | |
| 454 | /* FIXME: log */ | |
| 455 | free(pevent); | |
| 456 | pevent=0; | |
| 457 | break; | |
| 458 | } | |
| 459 | ||
| 460 | /* FIXME: ensure no bytes are remaining */ | |
| 461 | ||
| 462 | return pevent; | |
| 463 | } | |
| 464 | ||
| 465 | #ifdef EVENT_DEBUG | |
| 466 | const char *icq_EventDump(icq_Event *pevent) | |
| 467 | { | |
| 468 | static char buf[255]; | |
| 469 | ||
| 470 | sprintf("%s event sent to uin %ld { %s }", (pevent->eventName)(pevent), | |
| 471 | pevent->uin, (pevent->eventDump)(pevent) ); | |
| 472 | ||
| 473 | return buf; | |
| 474 | } | |
| 475 | #endif |