~ubuntu-branches/ubuntu/raring/pidgin/raring

1 by Ari Pollak
Import upstream version 2.0.0+dfsg.1
1
/**
2
 * @file msg.c Message functions
3
 *
4
 * purple
5
 *
6
 * Purple is the legal property of its developers, whose names are too numerous
7
 * to list here.  Please refer to the COPYRIGHT file distributed with this
8
 * source distribution.
9
 *
10
 * This program is free software; you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation; either version 2 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program; if not, write to the Free Software
1.1.4 by Sebastien Bacher
Import upstream version 2.2.0
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
1 by Ari Pollak
Import upstream version 2.0.0+dfsg.1
23
 */
24
#include "msn.h"
25
#include "msg.h"
26
27
MsnMessage *
28
msn_message_new(MsnMsgType type)
29
{
30
	MsnMessage *msg;
31
32
	msg = g_new0(MsnMessage, 1);
33
	msg->type = type;
34
35
#ifdef MSN_DEBUG_MSG
36
	purple_debug_info("msn", "message new (%p)(%d)\n", msg, type);
37
#endif
38
39
	msg->attr_table = g_hash_table_new_full(g_str_hash, g_str_equal,
40
											g_free, g_free);
41
42
	msn_message_ref(msg);
43
44
	return msg;
45
}
46
47
void
48
msn_message_destroy(MsnMessage *msg)
49
{
50
	g_return_if_fail(msg != NULL);
51
52
	if (msg->ref_count > 0)
53
	{
54
		msn_message_unref(msg);
55
56
		return;
57
	}
58
59
#ifdef MSN_DEBUG_MSG
60
	purple_debug_info("msn", "message destroy (%p)\n", msg);
61
#endif
62
1.1.7 by Pedro Fragoso
Import upstream version 2.3.1
63
	g_free(msg->remote_user);
64
	g_free(msg->body);
65
	g_free(msg->content_type);
66
	g_free(msg->charset);
1 by Ari Pollak
Import upstream version 2.0.0+dfsg.1
67
68
	g_hash_table_destroy(msg->attr_table);
69
	g_list_free(msg->attr_list);
70
71
	g_free(msg);
72
}
73
74
MsnMessage *
75
msn_message_ref(MsnMessage *msg)
76
{
77
	g_return_val_if_fail(msg != NULL, NULL);
78
79
	msg->ref_count++;
80
81
#ifdef MSN_DEBUG_MSG
82
	purple_debug_info("msn", "message ref (%p)[%d]\n", msg, msg->ref_count);
83
#endif
84
85
	return msg;
86
}
87
88
MsnMessage *
89
msn_message_unref(MsnMessage *msg)
90
{
91
	g_return_val_if_fail(msg != NULL, NULL);
92
	g_return_val_if_fail(msg->ref_count > 0, NULL);
93
94
	msg->ref_count--;
95
96
#ifdef MSN_DEBUG_MSG
97
	purple_debug_info("msn", "message unref (%p)[%d]\n", msg, msg->ref_count);
98
#endif
99
100
	if (msg->ref_count == 0)
101
	{
102
		msn_message_destroy(msg);
103
104
		return NULL;
105
	}
106
107
	return msg;
108
}
109
110
MsnMessage *
111
msn_message_new_plain(const char *message)
112
{
113
	MsnMessage *msg;
114
	char *message_cr;
115
116
	msg = msn_message_new(MSN_MSG_TEXT);
1.1.14 by Sebastien Bacher
Import upstream version 2.5.2
117
	msg->retries = 1;
1 by Ari Pollak
Import upstream version 2.0.0+dfsg.1
118
	msn_message_set_attr(msg, "User-Agent", PACKAGE_NAME "/" VERSION);
119
	msn_message_set_content_type(msg, "text/plain");
120
	msn_message_set_charset(msg, "UTF-8");
121
	msn_message_set_flag(msg, 'A');
122
	msn_message_set_attr(msg, "X-MMS-IM-Format",
1.1.7 by Pedro Fragoso
Import upstream version 2.3.1
123
						 "FN=MS%20Sans%20Serif; EF=; CO=0; CS=86;PF=0");
1 by Ari Pollak
Import upstream version 2.0.0+dfsg.1
124
125
	message_cr = purple_str_add_cr(message);
126
	msn_message_set_bin_data(msg, message_cr, strlen(message_cr));
127
	g_free(message_cr);
128
129
	return msg;
130
}
131
132
MsnMessage *
133
msn_message_new_msnslp(void)
134
{
135
	MsnMessage *msg;
136
137
	msg = msn_message_new(MSN_MSG_SLP);
138
139
	msn_message_set_attr(msg, "User-Agent", NULL);
140
141
	msg->msnslp_message = TRUE;
142
143
	msn_message_set_flag(msg, 'D');
144
	msn_message_set_content_type(msg, "application/x-msnmsgrp2p");
145
146
	return msg;
147
}
148
149
MsnMessage *
150
msn_message_new_nudge(void)
151
{
152
	MsnMessage *msg;
153
154
	msg = msn_message_new(MSN_MSG_NUDGE);
1.1.12 by Sebastien Bacher
Import upstream version 2.5.0
155
	msn_message_set_content_type(msg, "text/x-msnmsgr-datacast");
1 by Ari Pollak
Import upstream version 2.0.0+dfsg.1
156
	msn_message_set_flag(msg, 'N');
1.1.12 by Sebastien Bacher
Import upstream version 2.5.0
157
	msn_message_set_bin_data(msg, "ID: 1\r\n", 7);
1 by Ari Pollak
Import upstream version 2.0.0+dfsg.1
158
159
	return msg;
160
}
161
162
void
163
msn_message_parse_slp_body(MsnMessage *msg, const char *body, size_t len)
164
{
165
	MsnSlpHeader header;
166
	const char *tmp;
167
	int body_len;
168
169
	tmp = body;
170
171
	if (len < sizeof(header)) {
172
		g_return_if_reached();
173
	}
174
175
	/* Import the header. */
176
	memcpy(&header, tmp, sizeof(header));
177
	tmp += sizeof(header);
178
179
	msg->msnslp_header.session_id = GUINT32_FROM_LE(header.session_id);
180
	msg->msnslp_header.id         = GUINT32_FROM_LE(header.id);
181
	msg->msnslp_header.offset     = GUINT64_FROM_LE(header.offset);
182
	msg->msnslp_header.total_size = GUINT64_FROM_LE(header.total_size);
183
	msg->msnslp_header.length     = GUINT32_FROM_LE(header.length);
184
	msg->msnslp_header.flags      = GUINT32_FROM_LE(header.flags);
185
	msg->msnslp_header.ack_id     = GUINT32_FROM_LE(header.ack_id);
186
	msg->msnslp_header.ack_sub_id = GUINT32_FROM_LE(header.ack_sub_id);
187
	msg->msnslp_header.ack_size   = GUINT64_FROM_LE(header.ack_size);
188
189
	/* Import the body. */
190
	body_len = len - (tmp - body);
191
	/* msg->body_len = msg->msnslp_header.length; */
192
193
	if (body_len > 0) {
194
		msg->body_len = len - (tmp - body);
195
		msg->body = g_malloc0(msg->body_len + 1);
196
		memcpy(msg->body, tmp, msg->body_len);
197
		tmp += body_len;
198
	}
199
}
200
201
void
202
msn_message_parse_payload(MsnMessage *msg,
1.1.7 by Pedro Fragoso
Import upstream version 2.3.1
203
						  const char *payload, size_t payload_len,
204
						  const char *line_dem,const char *body_dem)
1 by Ari Pollak
Import upstream version 2.0.0+dfsg.1
205
{
206
	char *tmp_base, *tmp;
207
	const char *content_type;
208
	char *end;
209
	char **elems, **cur, **tokens;
210
211
	g_return_if_fail(payload != NULL);
212
	tmp_base = tmp = g_malloc0(payload_len + 1);
213
	memcpy(tmp_base, payload, payload_len);
214
215
	/* Parse the attributes. */
1.1.7 by Pedro Fragoso
Import upstream version 2.3.1
216
	end = strstr(tmp, body_dem);
1 by Ari Pollak
Import upstream version 2.0.0+dfsg.1
217
	/* TODO? some clients use \r delimiters instead of \r\n, the official client
218
	 * doesn't send such messages, but does handle receiving them. We'll just
219
	 * avoid crashing for now */
220
	if (end == NULL) {
221
		g_free(tmp_base);
222
		g_return_if_reached();
223
	}
224
	*end = '\0';
225
1.1.7 by Pedro Fragoso
Import upstream version 2.3.1
226
	elems = g_strsplit(tmp, line_dem, 0);
1 by Ari Pollak
Import upstream version 2.0.0+dfsg.1
227
228
	for (cur = elems; *cur != NULL; cur++)
229
	{
230
		const char *key, *value;
231
232
		tokens = g_strsplit(*cur, ": ", 2);
233
234
		key = tokens[0];
235
		value = tokens[1];
236
1.1.7 by Pedro Fragoso
Import upstream version 2.3.1
237
		/*if not MIME content ,then return*/
1 by Ari Pollak
Import upstream version 2.0.0+dfsg.1
238
		if (!strcmp(key, "MIME-Version"))
239
		{
240
			g_strfreev(tokens);
241
			continue;
242
		}
243
244
		if (!strcmp(key, "Content-Type"))
245
		{
246
			char *charset, *c;
247
248
			if ((c = strchr(value, ';')) != NULL)
249
			{
250
				if ((charset = strchr(c, '=')) != NULL)
251
				{
252
					charset++;
253
					msn_message_set_charset(msg, charset);
254
				}
255
256
				*c = '\0';
257
			}
258
259
			msn_message_set_content_type(msg, value);
260
		}
261
		else
262
		{
263
			msn_message_set_attr(msg, key, value);
264
		}
265
266
		g_strfreev(tokens);
267
	}
268
269
	g_strfreev(elems);
270
271
	/* Proceed to the end of the "\r\n\r\n" */
1.1.7 by Pedro Fragoso
Import upstream version 2.3.1
272
	tmp = end + strlen(body_dem);
1 by Ari Pollak
Import upstream version 2.0.0+dfsg.1
273
274
	/* Now we *should* be at the body. */
275
	content_type = msn_message_get_content_type(msg);
276
277
	if (content_type != NULL &&
278
		!strcmp(content_type, "application/x-msnmsgrp2p"))
279
	{
280
		MsnSlpHeader header;
281
		MsnSlpFooter footer;
282
		int body_len;
283
284
		if (payload_len - (tmp - tmp_base) < sizeof(header)) {
285
			g_free(tmp_base);
286
			g_return_if_reached();
287
		}
288
289
		msg->msnslp_message = TRUE;
290
291
		/* Import the header. */
292
		memcpy(&header, tmp, sizeof(header));
293
		tmp += sizeof(header);
294
295
		msg->msnslp_header.session_id = GUINT32_FROM_LE(header.session_id);
296
		msg->msnslp_header.id         = GUINT32_FROM_LE(header.id);
297
		msg->msnslp_header.offset     = GUINT64_FROM_LE(header.offset);
298
		msg->msnslp_header.total_size = GUINT64_FROM_LE(header.total_size);
299
		msg->msnslp_header.length     = GUINT32_FROM_LE(header.length);
300
		msg->msnslp_header.flags      = GUINT32_FROM_LE(header.flags);
301
		msg->msnslp_header.ack_id     = GUINT32_FROM_LE(header.ack_id);
302
		msg->msnslp_header.ack_sub_id = GUINT32_FROM_LE(header.ack_sub_id);
303
		msg->msnslp_header.ack_size   = GUINT64_FROM_LE(header.ack_size);
304
305
		body_len = payload_len - (tmp - tmp_base) - sizeof(footer);
306
307
		/* Import the body. */
308
		if (body_len > 0) {
309
			msg->body_len = body_len;
1.1.7 by Pedro Fragoso
Import upstream version 2.3.1
310
			g_free(msg->body);
1 by Ari Pollak
Import upstream version 2.0.0+dfsg.1
311
			msg->body = g_malloc0(msg->body_len + 1);
312
			memcpy(msg->body, tmp, msg->body_len);
313
			tmp += body_len;
314
		}
315
316
		/* Import the footer. */
317
		if (body_len >= 0) {
318
			memcpy(&footer, tmp, sizeof(footer));
319
			tmp += sizeof(footer);
320
			msg->msnslp_footer.value = GUINT32_FROM_BE(footer.value);
321
		}
322
	}
323
	else
324
	{
325
		if (payload_len - (tmp - tmp_base) > 0) {
326
			msg->body_len = payload_len - (tmp - tmp_base);
1.1.7 by Pedro Fragoso
Import upstream version 2.3.1
327
			g_free(msg->body);
1 by Ari Pollak
Import upstream version 2.0.0+dfsg.1
328
			msg->body = g_malloc0(msg->body_len + 1);
329
			memcpy(msg->body, tmp, msg->body_len);
330
		}
331
	}
332
333
	g_free(tmp_base);
334
}
335
336
MsnMessage *
337
msn_message_new_from_cmd(MsnSession *session, MsnCommand *cmd)
338
{
339
	MsnMessage *msg;
340
341
	g_return_val_if_fail(cmd != NULL, NULL);
342
343
	msg = msn_message_new(MSN_MSG_UNKNOWN);
344
345
	msg->remote_user = g_strdup(cmd->params[0]);
346
	/* msg->size = atoi(cmd->params[2]); */
347
	msg->cmd = cmd;
348
349
	return msg;
350
}
351
352
char *
353
msn_message_gen_slp_body(MsnMessage *msg, size_t *ret_size)
354
{
355
	MsnSlpHeader header;
356
357
	char *tmp, *base;
358
	const void *body;
359
	size_t len, body_len;
360
361
	g_return_val_if_fail(msg != NULL, NULL);
362
363
	len = MSN_BUF_LEN;
364
365
	base = tmp = g_malloc(len + 1);
366
367
	body = msn_message_get_bin_data(msg, &body_len);
368
369
	header.session_id = GUINT32_TO_LE(msg->msnslp_header.session_id);
370
	header.id         = GUINT32_TO_LE(msg->msnslp_header.id);
371
	header.offset     = GUINT64_TO_LE(msg->msnslp_header.offset);
372
	header.total_size = GUINT64_TO_LE(msg->msnslp_header.total_size);
373
	header.length     = GUINT32_TO_LE(msg->msnslp_header.length);
374
	header.flags      = GUINT32_TO_LE(msg->msnslp_header.flags);
375
	header.ack_id     = GUINT32_TO_LE(msg->msnslp_header.ack_id);
376
	header.ack_sub_id = GUINT32_TO_LE(msg->msnslp_header.ack_sub_id);
377
	header.ack_size   = GUINT64_TO_LE(msg->msnslp_header.ack_size);
378
379
	memcpy(tmp, &header, 48);
380
	tmp += 48;
381
382
	if (body != NULL)
383
	{
384
		memcpy(tmp, body, body_len);
385
		tmp += body_len;
386
	}
387
388
	if (ret_size != NULL)
389
		*ret_size = tmp - base;
390
391
	return base;
392
}
393
394
char *
395
msn_message_gen_payload(MsnMessage *msg, size_t *ret_size)
396
{
397
	GList *l;
398
	char *n, *base, *end;
399
	int len;
1.1.4 by Sebastien Bacher
Import upstream version 2.2.0
400
	size_t body_len = 0;
1 by Ari Pollak
Import upstream version 2.0.0+dfsg.1
401
	const void *body;
402
403
	g_return_val_if_fail(msg != NULL, NULL);
404
405
	len = MSN_BUF_LEN;
406
407
	base = n = end = g_malloc(len + 1);
408
	end += len;
409
410
	/* Standard header. */
411
	if (msg->charset == NULL)
412
	{
413
		g_snprintf(n, len,
414
				   "MIME-Version: 1.0\r\n"
415
				   "Content-Type: %s\r\n",
416
				   msg->content_type);
417
	}
418
	else
419
	{
420
		g_snprintf(n, len,
421
				   "MIME-Version: 1.0\r\n"
422
				   "Content-Type: %s; charset=%s\r\n",
423
				   msg->content_type, msg->charset);
424
	}
425
426
	n += strlen(n);
427
428
	for (l = msg->attr_list; l != NULL; l = l->next)
429
	{
430
		const char *key;
431
		const char *value;
432
433
		key = l->data;
434
		value = msn_message_get_attr(msg, key);
435
436
		g_snprintf(n, end - n, "%s: %s\r\n", key, value);
437
		n += strlen(n);
438
	}
439
440
	n += g_strlcpy(n, "\r\n", end - n);
441
442
	body = msn_message_get_bin_data(msg, &body_len);
443
444
	if (msg->msnslp_message)
445
	{
446
		MsnSlpHeader header;
447
		MsnSlpFooter footer;
448
449
		header.session_id = GUINT32_TO_LE(msg->msnslp_header.session_id);
450
		header.id         = GUINT32_TO_LE(msg->msnslp_header.id);
451
		header.offset     = GUINT64_TO_LE(msg->msnslp_header.offset);
452
		header.total_size = GUINT64_TO_LE(msg->msnslp_header.total_size);
453
		header.length     = GUINT32_TO_LE(msg->msnslp_header.length);
454
		header.flags      = GUINT32_TO_LE(msg->msnslp_header.flags);
455
		header.ack_id     = GUINT32_TO_LE(msg->msnslp_header.ack_id);
456
		header.ack_sub_id = GUINT32_TO_LE(msg->msnslp_header.ack_sub_id);
457
		header.ack_size   = GUINT64_TO_LE(msg->msnslp_header.ack_size);
458
459
		memcpy(n, &header, 48);
460
		n += 48;
461
462
		if (body != NULL)
463
		{
464
			memcpy(n, body, body_len);
465
466
			n += body_len;
467
		}
468
469
		footer.value = GUINT32_TO_BE(msg->msnslp_footer.value);
470
471
		memcpy(n, &footer, 4);
472
		n += 4;
473
	}
474
	else
475
	{
476
		if (body != NULL)
477
		{
478
			memcpy(n, body, body_len);
479
			n += body_len;
1.1.7 by Pedro Fragoso
Import upstream version 2.3.1
480
			*n = '\0';
1 by Ari Pollak
Import upstream version 2.0.0+dfsg.1
481
		}
482
	}
483
484
	if (ret_size != NULL)
485
	{
486
		*ret_size = n - base;
487
488
		if (*ret_size > 1664)
489
			*ret_size = 1664;
490
	}
491
492
	return base;
493
}
494
495
void
496
msn_message_set_flag(MsnMessage *msg, char flag)
497
{
498
	g_return_if_fail(msg != NULL);
499
	g_return_if_fail(flag != 0);
500
501
	msg->flag = flag;
502
}
503
504
char
505
msn_message_get_flag(const MsnMessage *msg)
506
{
507
	g_return_val_if_fail(msg != NULL, 0);
508
509
	return msg->flag;
510
}
511
512
void
513
msn_message_set_bin_data(MsnMessage *msg, const void *data, size_t len)
514
{
515
	g_return_if_fail(msg != NULL);
516
517
	/* There is no need to waste memory on data we cannot send anyway */
518
	if (len > 1664)
519
		len = 1664;
520
521
	if (msg->body != NULL)
522
		g_free(msg->body);
523
524
	if (data != NULL && len > 0)
525
	{
526
		msg->body = g_malloc0(len + 1);
527
		memcpy(msg->body, data, len);
528
		msg->body_len = len;
529
	}
530
	else
531
	{
532
		msg->body = NULL;
533
		msg->body_len = 0;
534
	}
535
}
536
537
const void *
538
msn_message_get_bin_data(const MsnMessage *msg, size_t *len)
539
{
540
	g_return_val_if_fail(msg != NULL, NULL);
541
542
	if (len)
543
		*len = msg->body_len;
544
545
	return msg->body;
546
}
547
548
void
549
msn_message_set_content_type(MsnMessage *msg, const char *type)
550
{
551
	g_return_if_fail(msg != NULL);
552
1.1.7 by Pedro Fragoso
Import upstream version 2.3.1
553
	g_free(msg->content_type);
554
	msg->content_type = g_strdup(type);
1 by Ari Pollak
Import upstream version 2.0.0+dfsg.1
555
}
556
557
const char *
558
msn_message_get_content_type(const MsnMessage *msg)
559
{
560
	g_return_val_if_fail(msg != NULL, NULL);
561
562
	return msg->content_type;
563
}
564
565
void
566
msn_message_set_charset(MsnMessage *msg, const char *charset)
567
{
568
	g_return_if_fail(msg != NULL);
569
1.1.7 by Pedro Fragoso
Import upstream version 2.3.1
570
	g_free(msg->charset);
571
	msg->charset = g_strdup(charset);
1 by Ari Pollak
Import upstream version 2.0.0+dfsg.1
572
}
573
574
const char *
575
msn_message_get_charset(const MsnMessage *msg)
576
{
577
	g_return_val_if_fail(msg != NULL, NULL);
578
579
	return msg->charset;
580
}
581
582
void
583
msn_message_set_attr(MsnMessage *msg, const char *attr, const char *value)
584
{
585
	const char *temp;
586
	char *new_attr;
587
588
	g_return_if_fail(msg != NULL);
589
	g_return_if_fail(attr != NULL);
590
591
	temp = msn_message_get_attr(msg, attr);
592
593
	if (value == NULL)
594
	{
595
		if (temp != NULL)
596
		{
597
			GList *l;
598
599
			for (l = msg->attr_list; l != NULL; l = l->next)
600
			{
601
				if (!g_ascii_strcasecmp(l->data, attr))
602
				{
603
					msg->attr_list = g_list_remove(msg->attr_list, l->data);
604
605
					break;
606
				}
607
			}
608
609
			g_hash_table_remove(msg->attr_table, attr);
610
		}
611
612
		return;
613
	}
614
615
	new_attr = g_strdup(attr);
616
617
	g_hash_table_insert(msg->attr_table, new_attr, g_strdup(value));
618
619
	if (temp == NULL)
620
		msg->attr_list = g_list_append(msg->attr_list, new_attr);
621
}
622
623
const char *
624
msn_message_get_attr(const MsnMessage *msg, const char *attr)
625
{
626
	g_return_val_if_fail(msg != NULL, NULL);
627
	g_return_val_if_fail(attr != NULL, NULL);
628
629
	return g_hash_table_lookup(msg->attr_table, attr);
630
}
631
632
GHashTable *
633
msn_message_get_hashtable_from_body(const MsnMessage *msg)
634
{
635
	GHashTable *table;
636
	size_t body_len;
637
	const char *body;
638
	char **elems, **cur, **tokens, *body_str;
639
640
	g_return_val_if_fail(msg != NULL, NULL);
641
642
	table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
643
644
	body = msn_message_get_bin_data(msg, &body_len);
645
646
	g_return_val_if_fail(body != NULL, NULL);
647
648
	body_str = g_strndup(body, body_len);
649
	elems = g_strsplit(body_str, "\r\n", 0);
650
	g_free(body_str);
651
652
	for (cur = elems; *cur != NULL; cur++)
653
	{
654
		if (**cur == '\0')
655
			break;
656
657
		tokens = g_strsplit(*cur, ": ", 2);
658
1.1.7 by Pedro Fragoso
Import upstream version 2.3.1
659
		if (tokens[0] != NULL && tokens[1] != NULL) {
1 by Ari Pollak
Import upstream version 2.0.0+dfsg.1
660
			g_hash_table_insert(table, tokens[0], tokens[1]);
1.1.7 by Pedro Fragoso
Import upstream version 2.3.1
661
			g_free(tokens);
662
		} else
663
			g_strfreev(tokens);
1 by Ari Pollak
Import upstream version 2.0.0+dfsg.1
664
	}
665
666
	g_strfreev(elems);
667
668
	return table;
669
}
670
671
char *
672
msn_message_to_string(MsnMessage *msg)
673
{
674
	size_t body_len;
675
	const char *body;
676
677
	g_return_val_if_fail(msg != NULL, NULL);
678
	g_return_val_if_fail(msg->type == MSN_MSG_TEXT, NULL);
679
680
	body = msn_message_get_bin_data(msg, &body_len);
681
682
	return g_strndup(body, body_len);
683
}
684
685
void
686
msn_message_show_readable(MsnMessage *msg, const char *info,
687
						  gboolean text_body)
688
{
689
	GString *str;
690
	size_t body_len;
691
	const char *body;
692
	GList *l;
693
694
	g_return_if_fail(msg != NULL);
695
696
	str = g_string_new(NULL);
697
698
	/* Standard header. */
699
	if (msg->charset == NULL)
700
	{
701
		g_string_append_printf(str,
702
				   "MIME-Version: 1.0\r\n"
703
				   "Content-Type: %s\r\n",
704
				   msg->content_type);
705
	}
706
	else
707
	{
708
		g_string_append_printf(str,
709
				   "MIME-Version: 1.0\r\n"
710
				   "Content-Type: %s; charset=%s\r\n",
711
				   msg->content_type, msg->charset);
712
	}
713
714
	for (l = msg->attr_list; l; l = l->next)
715
	{
716
		char *key;
717
		const char *value;
718
719
		key = l->data;
720
		value = msn_message_get_attr(msg, key);
721
722
		g_string_append_printf(str, "%s: %s\r\n", key, value);
723
	}
724
725
	g_string_append(str, "\r\n");
726
727
	body = msn_message_get_bin_data(msg, &body_len);
728
729
	if (msg->msnslp_message)
730
	{
731
		g_string_append_printf(str, "Session ID: %u\r\n", msg->msnslp_header.session_id);
732
		g_string_append_printf(str, "ID:         %u\r\n", msg->msnslp_header.id);
733
		g_string_append_printf(str, "Offset:     %" G_GUINT64_FORMAT "\r\n", msg->msnslp_header.offset);
734
		g_string_append_printf(str, "Total size: %" G_GUINT64_FORMAT "\r\n", msg->msnslp_header.total_size);
735
		g_string_append_printf(str, "Length:     %u\r\n", msg->msnslp_header.length);
736
		g_string_append_printf(str, "Flags:      0x%x\r\n", msg->msnslp_header.flags);
737
		g_string_append_printf(str, "ACK ID:     %u\r\n", msg->msnslp_header.ack_id);
738
		g_string_append_printf(str, "SUB ID:     %u\r\n", msg->msnslp_header.ack_sub_id);
739
		g_string_append_printf(str, "ACK Size:   %" G_GUINT64_FORMAT "\r\n", msg->msnslp_header.ack_size);
740
741
#ifdef MSN_DEBUG_SLP_VERBOSE
742
		if (body != NULL)
743
		{
744
			if (text_body)
745
			{
746
				g_string_append_len(str, body, body_len);
747
				if (body[body_len - 1] == '\0')
748
				{
749
					str->len--;
750
					g_string_append(str, " 0x00");
751
				}
752
				g_string_append(str, "\r\n");
753
			}
754
			else
755
			{
756
				int i;
757
				for (i = 0; i < msg->body_len; i++)
758
				{
759
					g_string_append_printf(str, "%.2hhX ", body[i]);
760
					if ((i % 16) == 15)
761
						g_string_append(str, "\r\n");
762
				}
763
				g_string_append(str, "\r\n");
764
			}
765
		}
766
#endif
767
768
		g_string_append_printf(str, "Footer:     %u\r\n", msg->msnslp_footer.value);
769
	}
770
	else
771
	{
772
		if (body != NULL)
773
		{
774
			g_string_append_len(str, body, body_len);
775
			g_string_append(str, "\r\n");
776
		}
777
	}
778
779
	purple_debug_info("msn", "Message %s:\n{%s}\n", info, str->str);
780
781
	g_string_free(str, TRUE);
782
}