Mercurial > pidgin
comparison src/protocols/msn/msg.c @ 5309:e2e53316a21d
[gaim-migrate @ 5681]
Announcing the new MSN prpl! It probably has some bugs, and for the time
being, there is no file transfer. That's good though, because the current
MSN file transfer is a little broken. I've had many corrupted files. I'll
commit new file transfer code when it's written.
I want this heavily tested before 0.63! If you use MSN, please talk to
people on it. Let me know of any oddities, crashes, bugs, whatever. I'll
fix things as I find them.
committer: Tailor Script <tailor@pidgin.im>
| author | Christian Hammond <chipx86@chipx86.com> |
|---|---|
| date | Tue, 06 May 2003 02:06:56 +0000 |
| parents | abe4d103e300 |
| children | f4912a833ff6 |
comparison
equal
deleted
inserted
replaced
| 5308:6aa785e55d0f | 5309:e2e53316a21d |
|---|---|
| 1 /** | 1 /** |
| 2 * @file msg.c Message functions | 2 * @file msg.c Message functions |
| 3 * | 3 * |
| 4 * gaim | 4 * gaim |
| 5 * | 5 * |
| 6 * Copyright (C) 2003, Christian Hammond <chipx86@gnupdate.org> | 6 * Copyright (C) 2003 Christian Hammond <chipx86@gnupdate.org> |
| 7 * | 7 * |
| 8 * This program is free software; you can redistribute it and/or modify | 8 * This program is free software; you can redistribute it and/or modify |
| 9 * it under the terms of the GNU General Public License as published by | 9 * it under the terms of the GNU General Public License as published by |
| 10 * the Free Software Foundation; either version 2 of the License, or | 10 * the Free Software Foundation; either version 2 of the License, or |
| 11 * (at your option) any later version. | 11 * (at your option) any later version. |
| 16 * GNU General Public License for more details. | 16 * GNU General Public License for more details. |
| 17 * | 17 * |
| 18 * You should have received a copy of the GNU General Public License | 18 * You should have received a copy of the GNU General Public License |
| 19 * along with this program; if not, write to the Free Software | 19 * along with this program; if not, write to the Free Software |
| 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 21 * | |
| 22 */ | 21 */ |
| 23 #include "msn.h" | 22 #include "msn.h" |
| 24 | 23 #include "msg.h" |
| 25 int | 24 |
| 26 msn_write(int fd, void *data, int len) | 25 #define GET_NEXT(tmp) \ |
| 27 { | 26 while (*(tmp) && *(tmp) != ' ' && *(tmp) != '\r') \ |
| 28 gaim_debug(GAIM_DEBUG_MISC, "msn", "C: %s", (char *)data); | 27 (tmp)++; \ |
| 29 | 28 *(tmp)++ = '\0'; \ |
| 30 return write(fd, data, len); | 29 if (*(tmp) == '\n') *(tmp)++; \ |
| 31 } | 30 while (*(tmp) && *(tmp) == ' ') \ |
| 32 | 31 (tmp)++ |
| 32 | |
| 33 #define GET_NEXT_LINE(tmp) \ | |
| 34 while (*(tmp) && *(tmp) != '\r') \ | |
| 35 (tmp)++; \ | |
| 36 *(tmp)++ = '\0'; \ | |
| 37 if (*(tmp) == '\n') *(tmp)++ | |
| 38 | |
| 39 /* | |
| 40 * "MIME-Version: 1.0\r\n" == 19 | |
| 41 * "Content-Type: " == 14 | |
| 42 * "\r\n" == 2 | |
| 43 * "\r\n" before body == 2 | |
| 44 * ---- | |
| 45 * 37 | |
| 46 * MATH PAYS OFF!! | |
| 47 */ | |
| 48 #define MSN_MESSAGE_BASE_SIZE 37 | |
| 49 | |
| 50 MsnMessage * | |
| 51 msn_message_new(void) | |
| 52 { | |
| 53 MsnMessage *msg; | |
| 54 | |
| 55 msg = g_new0(MsnMessage, 1); | |
| 56 | |
| 57 msg->attr_table = g_hash_table_new_full(g_str_hash, g_str_equal, | |
| 58 g_free, g_free); | |
| 59 msg->size = MSN_MESSAGE_BASE_SIZE; | |
| 60 | |
| 61 msn_message_set_attr(msg, "User-Agent", "Gaim/" VERSION); | |
| 62 msn_message_set_content_type(msg, "text/plain"); | |
| 63 msn_message_set_charset(msg, "UTF-8"); | |
| 64 msn_message_set_flag(msg, 'N'); | |
| 65 | |
| 66 return msg; | |
| 67 } | |
| 68 | |
| 69 MsnMessage * | |
| 70 msn_message_new_from_str(MsnSession *session, const char *str) | |
| 71 { | |
| 72 MsnMessage *msg; | |
| 73 char *tmp, *field1, *field2, *c; | |
| 74 | |
| 75 g_return_val_if_fail(str != NULL, NULL); | |
| 76 g_return_val_if_fail(!g_ascii_strncasecmp(str, "MSG", 3), NULL); | |
| 77 | |
| 78 msg = msn_message_new(); | |
| 79 | |
| 80 tmp = g_strdup(str); | |
| 81 | |
| 82 GET_NEXT(tmp); /* Skip MSG */ | |
| 83 field1 = tmp; | |
| 84 | |
| 85 GET_NEXT(tmp); /* Skip the passport or TID */ | |
| 86 field2 = tmp; | |
| 87 | |
| 88 GET_NEXT(tmp); /* Skip the username or flag */ | |
| 89 msg->size = atoi(tmp); | |
| 90 | |
| 91 if (msg->size != strlen(strchr(str, '\n') + 1)) { | |
| 92 gaim_debug(GAIM_DEBUG_ERROR, "msn", | |
| 93 "Message size (%d) and string length (%d) " | |
| 94 "do not match!\n", msg->size, strlen(str)); | |
| 95 } | |
| 96 | |
| 97 /* | |
| 98 * We're going to make sure this is incoming by checking field1. | |
| 99 * If it has any non-numbers in it, it's incoming. Otherwise, outgoing. | |
| 100 */ | |
| 101 msg->incoming = FALSE; | |
| 102 | |
| 103 for (c = field1; *c != '\0'; c++) { | |
| 104 if (*c < '0' || *c > '9') { | |
| 105 msg->incoming = TRUE; | |
| 106 break; | |
| 107 } | |
| 108 } | |
| 109 | |
| 110 if (msg->incoming) { | |
| 111 msg->sender = msn_users_find_with_passport(session->users, field1); | |
| 112 | |
| 113 gaim_debug(GAIM_DEBUG_MISC, "msn", "incoming message: %s, %s\n", | |
| 114 field1, field2); | |
| 115 if (msg->sender == NULL) | |
| 116 msg->sender = msn_user_new(session, field1, field2); | |
| 117 else | |
| 118 msn_user_ref(msg->sender); | |
| 119 } | |
| 120 else { | |
| 121 msg->tid = atoi(field1); | |
| 122 msg->flag = *field2; | |
| 123 } | |
| 124 | |
| 125 /* Back to the parsination. */ | |
| 126 while (*tmp != '\r') { | |
| 127 char *key, *value; | |
| 128 | |
| 129 key = tmp; | |
| 130 | |
| 131 GET_NEXT(tmp); /* Key */ | |
| 132 | |
| 133 value = tmp; | |
| 134 | |
| 135 GET_NEXT_LINE(tmp); /* Value */ | |
| 136 | |
| 137 if ((c = strchr(key, ':')) != NULL) | |
| 138 *c = '\0'; | |
| 139 | |
| 140 if (!g_ascii_strcasecmp(key, "Content-Type")) { | |
| 141 char *charset; | |
| 142 | |
| 143 if ((c = strchr(value, ';')) != NULL) { | |
| 144 if ((charset = strchr(c, '=')) != NULL) { | |
| 145 charset++; | |
| 146 msn_message_set_charset(msg, charset); | |
| 147 } | |
| 148 | |
| 149 *c = '\0'; | |
| 150 } | |
| 151 | |
| 152 msn_message_set_content_type(msg, value); | |
| 153 } | |
| 154 else | |
| 155 msn_message_set_attr(msg, key, value); | |
| 156 } | |
| 157 | |
| 158 /* "\r\n" */ | |
| 159 tmp += 2; | |
| 160 | |
| 161 /* Now we *should* be at the body. */ | |
| 162 msn_message_set_body(msg, tmp); | |
| 163 | |
| 164 /* Done! */ | |
| 165 | |
| 166 return msg; | |
| 167 } | |
| 168 | |
| 169 void | |
| 170 msn_message_destroy(MsnMessage *msg) | |
| 171 { | |
| 172 g_return_if_fail(msg != NULL); | |
| 173 | |
| 174 if (msg->sender != NULL) | |
| 175 msn_user_unref(msg->sender); | |
| 176 | |
| 177 if (msg->receiver != NULL) | |
| 178 msn_user_unref(msg->receiver); | |
| 179 | |
| 180 if (msg->body != NULL) | |
| 181 g_free(msg->body); | |
| 182 | |
| 183 if (msg->content_type != NULL) | |
| 184 g_free(msg->content_type); | |
| 185 | |
| 186 if (msg->charset != NULL) | |
| 187 g_free(msg->charset); | |
| 188 | |
| 189 g_hash_table_destroy(msg->attr_table); | |
| 190 g_list_free(msg->attr_list); | |
| 191 | |
| 192 g_free(msg); | |
| 193 } | |
| 194 | |
| 195 char * | |
| 196 msn_message_build_string(const MsnMessage *msg) | |
| 197 { | |
| 198 GList *l; | |
| 199 char *str; | |
| 200 char buf[MSN_BUF_LEN]; | |
| 201 int len; | |
| 202 | |
| 203 /* | |
| 204 * Okay, how we do things here is just bad. I don't like writing to | |
| 205 * a static buffer and then copying to the string. Unfortunately, | |
| 206 * just trying to append to the string is causing issues.. Such as | |
| 207 * the string you're appending to being erased. Ugh. So, this is | |
| 208 * good enough for now. | |
| 209 * | |
| 210 * -- ChipX86 | |
| 211 */ | |
| 212 g_return_val_if_fail(msg != NULL, NULL); | |
| 213 | |
| 214 if (msn_message_is_incoming(msg)) { | |
| 215 MsnUser *sender = msn_message_get_sender(msg); | |
| 216 | |
| 217 g_snprintf(buf, sizeof(buf), "MSG %s %s %d\r\n", | |
| 218 msn_user_get_passport(sender), msn_user_get_name(sender), | |
| 219 msg->size); | |
| 220 } | |
| 221 else { | |
| 222 g_snprintf(buf, sizeof(buf), "MSG %d %c %d\r\n", | |
| 223 msn_message_get_transaction_id(msg), | |
| 224 msn_message_get_flag(msg), msg->size); | |
| 225 } | |
| 226 | |
| 227 len = strlen(buf) + msg->size + 1; | |
| 228 | |
| 229 str = g_new0(char, len); | |
| 230 | |
| 231 g_strlcpy(str, buf, len); | |
| 232 | |
| 233 /* Standard header. */ | |
| 234 if (msg->charset == NULL) { | |
| 235 g_snprintf(buf, sizeof(buf), | |
| 236 "MIME-Version: 1.0\r\n" | |
| 237 "Content-Type: %s\r\n", | |
| 238 msg->content_type); | |
| 239 } | |
| 240 else { | |
| 241 g_snprintf(buf, sizeof(buf), | |
| 242 "MIME-Version: 1.0\r\n" | |
| 243 "Content-Type: %s; charset=%s\r\n", | |
| 244 msg->content_type, msg->charset); | |
| 245 } | |
| 246 | |
| 247 g_strlcat(str, buf, len); | |
| 248 | |
| 249 for (l = msg->attr_list; l != NULL; l = l->next) { | |
| 250 const char *key = (char *)l->data; | |
| 251 const char *value; | |
| 252 | |
| 253 value = msn_message_get_attr(msg, key); | |
| 254 | |
| 255 g_snprintf(buf, sizeof(buf), "%s: %s\r\n", key, value); | |
| 256 | |
| 257 g_strlcat(str, buf, len); | |
| 258 } | |
| 259 | |
| 260 g_snprintf(buf, sizeof(buf), "\r\n%s", msn_message_get_body(msg)); | |
| 261 | |
| 262 g_strlcat(str, buf, len); | |
| 263 | |
| 264 return str; | |
| 265 } | |
| 266 | |
| 267 gboolean | |
| 268 msn_message_is_outgoing(const MsnMessage *msg) | |
| 269 { | |
| 270 g_return_val_if_fail(msg != NULL, FALSE); | |
| 271 | |
| 272 return !msg->incoming; | |
| 273 } | |
| 274 | |
| 275 gboolean | |
| 276 msn_message_is_incoming(const MsnMessage *msg) | |
| 277 { | |
| 278 g_return_val_if_fail(msg != NULL, FALSE); | |
| 279 | |
| 280 return msg->incoming; | |
| 281 } | |
| 282 | |
| 283 void | |
| 284 msn_message_set_sender(MsnMessage *msg, MsnUser *user) | |
| 285 { | |
| 286 g_return_if_fail(msg != NULL); | |
| 287 g_return_if_fail(user != NULL); | |
| 288 | |
| 289 msg->sender = user; | |
| 290 | |
| 291 msn_user_ref(msg->sender); | |
| 292 } | |
| 293 | |
| 294 MsnUser * | |
| 295 msn_message_get_sender(const MsnMessage *msg) | |
| 296 { | |
| 297 g_return_val_if_fail(msg != NULL, NULL); | |
| 298 | |
| 299 return msg->sender; | |
| 300 } | |
| 301 | |
| 302 void | |
| 303 msn_message_set_receiver(MsnMessage *msg, MsnUser *user) | |
| 304 { | |
| 305 g_return_if_fail(msg != NULL); | |
| 306 g_return_if_fail(user != NULL); | |
| 307 | |
| 308 msg->receiver = user; | |
| 309 | |
| 310 msn_user_ref(msg->receiver); | |
| 311 } | |
| 312 | |
| 313 MsnUser * | |
| 314 msn_message_get_receiver(const MsnMessage *msg) | |
| 315 { | |
| 316 g_return_val_if_fail(msg != NULL, NULL); | |
| 317 | |
| 318 return msg->receiver; | |
| 319 } | |
| 320 | |
| 321 void | |
| 322 msn_message_set_transaction_id(MsnMessage *msg, unsigned int tid) | |
| 323 { | |
| 324 g_return_if_fail(msg != NULL); | |
| 325 g_return_if_fail(tid > 0); | |
| 326 | |
| 327 msg->tid = tid; | |
| 328 } | |
| 329 | |
| 330 unsigned int | |
| 331 msn_message_get_transaction_id(const MsnMessage *msg) | |
| 332 { | |
| 333 g_return_val_if_fail(msg != NULL, 0); | |
| 334 | |
| 335 return msg->tid; | |
| 336 } | |
| 337 | |
| 338 void | |
| 339 msn_message_set_flag(MsnMessage *msg, char flag) | |
| 340 { | |
| 341 g_return_if_fail(msg != NULL); | |
| 342 g_return_if_fail(flag != 0); | |
| 343 | |
| 344 msg->flag = flag; | |
| 345 } | |
| 346 | |
| 347 char | |
| 348 msn_message_get_flag(const MsnMessage *msg) | |
| 349 { | |
| 350 g_return_val_if_fail(msg != NULL, 0); | |
| 351 | |
| 352 return msg->flag; | |
| 353 } | |
| 354 | |
| 355 void | |
| 356 msn_message_set_body(MsnMessage *msg, const char *body) | |
| 357 { | |
| 358 g_return_if_fail(msg != NULL); | |
| 359 g_return_if_fail(body != NULL); | |
| 360 | |
| 361 if (msg->body != NULL) { | |
| 362 msg->size -= strlen(msg->body); | |
| 363 g_free(msg->body); | |
| 364 } | |
| 365 | |
| 366 msg->body = g_strdup(body); | |
| 367 | |
| 368 msg->size += strlen(body); | |
| 369 } | |
| 370 | |
| 371 const char * | |
| 372 msn_message_get_body(const MsnMessage *msg) | |
| 373 { | |
| 374 g_return_val_if_fail(msg != NULL, NULL); | |
| 375 | |
| 376 return msg->body; | |
| 377 } | |
| 378 | |
| 379 void | |
| 380 msn_message_set_content_type(MsnMessage *msg, const char *type) | |
| 381 { | |
| 382 g_return_if_fail(msg != NULL); | |
| 383 g_return_if_fail(type != NULL); | |
| 384 | |
| 385 if (msg->content_type != NULL) { | |
| 386 msg->size -= strlen(msg->content_type); | |
| 387 g_free(msg->content_type); | |
| 388 } | |
| 389 | |
| 390 msg->content_type = g_strdup(type); | |
| 391 | |
| 392 msg->size += strlen(type); | |
| 393 } | |
| 394 | |
| 395 const char * | |
| 396 msn_message_get_content_type(const MsnMessage *msg) | |
| 397 { | |
| 398 g_return_val_if_fail(msg != NULL, NULL); | |
| 399 | |
| 400 return msg->content_type; | |
| 401 } | |
| 402 | |
| 403 void | |
| 404 msn_message_set_charset(MsnMessage *msg, const char *charset) | |
| 405 { | |
| 406 g_return_if_fail(msg != NULL); | |
| 407 | |
| 408 if (msg->charset != NULL) { | |
| 409 msg->size -= strlen(msg->charset) + strlen("; charset="); | |
| 410 g_free(msg->charset); | |
| 411 } | |
| 412 | |
| 413 if (charset != NULL) { | |
| 414 msg->charset = g_strdup(charset); | |
| 415 | |
| 416 msg->size += strlen(charset) + strlen("; charset="); | |
| 417 } | |
| 418 else | |
| 419 msg->charset = NULL; | |
| 420 } | |
| 421 | |
| 422 const char * | |
| 423 msn_message_get_charset(const MsnMessage *msg) | |
| 424 { | |
| 425 g_return_val_if_fail(msg != NULL, NULL); | |
| 426 | |
| 427 return msg->charset; | |
| 428 } | |
| 429 | |
| 430 void | |
| 431 msn_message_set_attr(MsnMessage *msg, const char *attr, const char *value) | |
| 432 { | |
| 433 const char *temp; | |
| 434 char *new_attr; | |
| 435 | |
| 436 g_return_if_fail(msg != NULL); | |
| 437 g_return_if_fail(attr != NULL); | |
| 438 | |
| 439 temp = msn_message_get_attr(msg, attr); | |
| 440 | |
| 441 if (value == NULL) { | |
| 442 if (temp != NULL) { | |
| 443 GList *l; | |
| 444 | |
| 445 for (l = msg->attr_list; l != NULL; l = l->next) { | |
| 446 if (!g_ascii_strcasecmp(l->data, attr)) { | |
| 447 msg->attr_list = g_list_remove(msg->attr_list, l->data); | |
| 448 | |
| 449 break; | |
| 450 } | |
| 451 } | |
| 452 | |
| 453 g_hash_table_remove(msg->attr_table, attr); | |
| 454 | |
| 455 msg->size -= strlen(temp) + strlen(attr) + 4; | |
| 456 } | |
| 457 | |
| 458 return; | |
| 459 } | |
| 460 | |
| 461 new_attr = g_strdup(attr); | |
| 462 | |
| 463 g_hash_table_insert(msg->attr_table, new_attr, g_strdup(value)); | |
| 464 | |
| 465 if (temp == NULL) { | |
| 466 msg->attr_list = g_list_append(msg->attr_list, new_attr); | |
| 467 msg->size += strlen(attr) + 4; | |
| 468 } | |
| 469 else | |
| 470 msg->size -= strlen(temp); | |
| 471 | |
| 472 msg->size += strlen(value); | |
| 473 } | |
| 474 | |
| 475 const char * | |
| 476 msn_message_get_attr(const MsnMessage *msg, const char *attr) | |
| 477 { | |
| 478 g_return_val_if_fail(msg != NULL, NULL); | |
| 479 g_return_val_if_fail(attr != NULL, NULL); | |
| 480 | |
| 481 return g_hash_table_lookup(msg->attr_table, attr); | |
| 482 } | |
| 483 | |
| 484 GHashTable * | |
| 485 msn_message_get_hashtable_from_body(const MsnMessage *msg) | |
| 486 { | |
| 487 GHashTable *table; | |
| 488 char *body, *s, *c; | |
| 489 | |
| 490 g_return_val_if_fail(msg != NULL, NULL); | |
| 491 g_return_val_if_fail(msn_message_get_body(msg) != NULL, NULL); | |
| 492 | |
| 493 s = body = g_strdup(msn_message_get_body(msg)); | |
| 494 | |
| 495 table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); | |
| 496 | |
| 497 while (*s != '\r') { | |
| 498 char *key, *value; | |
| 499 | |
| 500 key = s; | |
| 501 | |
| 502 GET_NEXT(s); | |
| 503 | |
| 504 value = s; | |
| 505 | |
| 506 GET_NEXT_LINE(s); | |
| 507 | |
| 508 if ((c = strchr(key, ':')) != NULL) { | |
| 509 *c = '\0'; | |
| 510 | |
| 511 g_hash_table_insert(table, g_strdup(key), g_strdup(value)); | |
| 512 } | |
| 513 } | |
| 514 | |
| 515 g_free(body); | |
| 516 | |
| 517 return table; | |
| 518 } | |
| 519 |
