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