Mercurial > pidgin.yaz
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 |