Mercurial > pidgin.yaz
diff 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 |
line wrap: on
line diff
--- a/src/protocols/msn/msg.c Tue May 06 00:34:54 2003 +0000 +++ b/src/protocols/msn/msg.c Tue May 06 02:06:56 2003 +0000 @@ -3,7 +3,7 @@ * * gaim * - * Copyright (C) 2003, Christian Hammond <chipx86@gnupdate.org> + * Copyright (C) 2003 Christian Hammond <chipx86@gnupdate.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,15 +18,502 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include "msn.h" +#include "msg.h" -int -msn_write(int fd, void *data, int len) +#define GET_NEXT(tmp) \ + while (*(tmp) && *(tmp) != ' ' && *(tmp) != '\r') \ + (tmp)++; \ + *(tmp)++ = '\0'; \ + if (*(tmp) == '\n') *(tmp)++; \ + while (*(tmp) && *(tmp) == ' ') \ + (tmp)++ + +#define GET_NEXT_LINE(tmp) \ + while (*(tmp) && *(tmp) != '\r') \ + (tmp)++; \ + *(tmp)++ = '\0'; \ + if (*(tmp) == '\n') *(tmp)++ + +/* + * "MIME-Version: 1.0\r\n" == 19 + * "Content-Type: " == 14 + * "\r\n" == 2 + * "\r\n" before body == 2 + * ---- + * 37 + * MATH PAYS OFF!! + */ +#define MSN_MESSAGE_BASE_SIZE 37 + +MsnMessage * +msn_message_new(void) +{ + MsnMessage *msg; + + msg = g_new0(MsnMessage, 1); + + msg->attr_table = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, g_free); + msg->size = MSN_MESSAGE_BASE_SIZE; + + msn_message_set_attr(msg, "User-Agent", "Gaim/" VERSION); + msn_message_set_content_type(msg, "text/plain"); + msn_message_set_charset(msg, "UTF-8"); + msn_message_set_flag(msg, 'N'); + + return msg; +} + +MsnMessage * +msn_message_new_from_str(MsnSession *session, const char *str) { - gaim_debug(GAIM_DEBUG_MISC, "msn", "C: %s", (char *)data); + MsnMessage *msg; + char *tmp, *field1, *field2, *c; + + g_return_val_if_fail(str != NULL, NULL); + g_return_val_if_fail(!g_ascii_strncasecmp(str, "MSG", 3), NULL); + + msg = msn_message_new(); + + tmp = g_strdup(str); + + GET_NEXT(tmp); /* Skip MSG */ + field1 = tmp; + + GET_NEXT(tmp); /* Skip the passport or TID */ + field2 = tmp; + + GET_NEXT(tmp); /* Skip the username or flag */ + msg->size = atoi(tmp); + + if (msg->size != strlen(strchr(str, '\n') + 1)) { + gaim_debug(GAIM_DEBUG_ERROR, "msn", + "Message size (%d) and string length (%d) " + "do not match!\n", msg->size, strlen(str)); + } + + /* + * We're going to make sure this is incoming by checking field1. + * If it has any non-numbers in it, it's incoming. Otherwise, outgoing. + */ + msg->incoming = FALSE; + + for (c = field1; *c != '\0'; c++) { + if (*c < '0' || *c > '9') { + msg->incoming = TRUE; + break; + } + } + + if (msg->incoming) { + msg->sender = msn_users_find_with_passport(session->users, field1); + + gaim_debug(GAIM_DEBUG_MISC, "msn", "incoming message: %s, %s\n", + field1, field2); + if (msg->sender == NULL) + msg->sender = msn_user_new(session, field1, field2); + else + msn_user_ref(msg->sender); + } + else { + msg->tid = atoi(field1); + msg->flag = *field2; + } + + /* Back to the parsination. */ + while (*tmp != '\r') { + char *key, *value; + + key = tmp; + + GET_NEXT(tmp); /* Key */ + + value = tmp; + + GET_NEXT_LINE(tmp); /* Value */ + + if ((c = strchr(key, ':')) != NULL) + *c = '\0'; + + if (!g_ascii_strcasecmp(key, "Content-Type")) { + char *charset; + + if ((c = strchr(value, ';')) != NULL) { + if ((charset = strchr(c, '=')) != NULL) { + charset++; + msn_message_set_charset(msg, charset); + } + + *c = '\0'; + } + + msn_message_set_content_type(msg, value); + } + else + msn_message_set_attr(msg, key, value); + } + + /* "\r\n" */ + tmp += 2; + + /* Now we *should* be at the body. */ + msn_message_set_body(msg, tmp); + + /* Done! */ + + return msg; +} - return write(fd, data, len); +void +msn_message_destroy(MsnMessage *msg) +{ + g_return_if_fail(msg != NULL); + + if (msg->sender != NULL) + msn_user_unref(msg->sender); + + if (msg->receiver != NULL) + msn_user_unref(msg->receiver); + + if (msg->body != NULL) + g_free(msg->body); + + if (msg->content_type != NULL) + g_free(msg->content_type); + + if (msg->charset != NULL) + g_free(msg->charset); + + g_hash_table_destroy(msg->attr_table); + g_list_free(msg->attr_list); + + g_free(msg); +} + +char * +msn_message_build_string(const MsnMessage *msg) +{ + GList *l; + char *str; + char buf[MSN_BUF_LEN]; + int len; + + /* + * Okay, how we do things here is just bad. I don't like writing to + * a static buffer and then copying to the string. Unfortunately, + * just trying to append to the string is causing issues.. Such as + * the string you're appending to being erased. Ugh. So, this is + * good enough for now. + * + * -- ChipX86 + */ + g_return_val_if_fail(msg != NULL, NULL); + + if (msn_message_is_incoming(msg)) { + MsnUser *sender = msn_message_get_sender(msg); + + g_snprintf(buf, sizeof(buf), "MSG %s %s %d\r\n", + msn_user_get_passport(sender), msn_user_get_name(sender), + msg->size); + } + else { + g_snprintf(buf, sizeof(buf), "MSG %d %c %d\r\n", + msn_message_get_transaction_id(msg), + msn_message_get_flag(msg), msg->size); + } + + len = strlen(buf) + msg->size + 1; + + str = g_new0(char, len); + + g_strlcpy(str, buf, len); + + /* Standard header. */ + if (msg->charset == NULL) { + g_snprintf(buf, sizeof(buf), + "MIME-Version: 1.0\r\n" + "Content-Type: %s\r\n", + msg->content_type); + } + else { + g_snprintf(buf, sizeof(buf), + "MIME-Version: 1.0\r\n" + "Content-Type: %s; charset=%s\r\n", + msg->content_type, msg->charset); + } + + g_strlcat(str, buf, len); + + for (l = msg->attr_list; l != NULL; l = l->next) { + const char *key = (char *)l->data; + const char *value; + + value = msn_message_get_attr(msg, key); + + g_snprintf(buf, sizeof(buf), "%s: %s\r\n", key, value); + + g_strlcat(str, buf, len); + } + + g_snprintf(buf, sizeof(buf), "\r\n%s", msn_message_get_body(msg)); + + g_strlcat(str, buf, len); + + return str; } +gboolean +msn_message_is_outgoing(const MsnMessage *msg) +{ + g_return_val_if_fail(msg != NULL, FALSE); + + return !msg->incoming; +} + +gboolean +msn_message_is_incoming(const MsnMessage *msg) +{ + g_return_val_if_fail(msg != NULL, FALSE); + + return msg->incoming; +} + +void +msn_message_set_sender(MsnMessage *msg, MsnUser *user) +{ + g_return_if_fail(msg != NULL); + g_return_if_fail(user != NULL); + + msg->sender = user; + + msn_user_ref(msg->sender); +} + +MsnUser * +msn_message_get_sender(const MsnMessage *msg) +{ + g_return_val_if_fail(msg != NULL, NULL); + + return msg->sender; +} + +void +msn_message_set_receiver(MsnMessage *msg, MsnUser *user) +{ + g_return_if_fail(msg != NULL); + g_return_if_fail(user != NULL); + + msg->receiver = user; + + msn_user_ref(msg->receiver); +} + +MsnUser * +msn_message_get_receiver(const MsnMessage *msg) +{ + g_return_val_if_fail(msg != NULL, NULL); + + return msg->receiver; +} + +void +msn_message_set_transaction_id(MsnMessage *msg, unsigned int tid) +{ + g_return_if_fail(msg != NULL); + g_return_if_fail(tid > 0); + + msg->tid = tid; +} + +unsigned int +msn_message_get_transaction_id(const MsnMessage *msg) +{ + g_return_val_if_fail(msg != NULL, 0); + + return msg->tid; +} + +void +msn_message_set_flag(MsnMessage *msg, char flag) +{ + g_return_if_fail(msg != NULL); + g_return_if_fail(flag != 0); + + msg->flag = flag; +} + +char +msn_message_get_flag(const MsnMessage *msg) +{ + g_return_val_if_fail(msg != NULL, 0); + + return msg->flag; +} + +void +msn_message_set_body(MsnMessage *msg, const char *body) +{ + g_return_if_fail(msg != NULL); + g_return_if_fail(body != NULL); + + if (msg->body != NULL) { + msg->size -= strlen(msg->body); + g_free(msg->body); + } + + msg->body = g_strdup(body); + + msg->size += strlen(body); +} + +const char * +msn_message_get_body(const MsnMessage *msg) +{ + g_return_val_if_fail(msg != NULL, NULL); + + return msg->body; +} + +void +msn_message_set_content_type(MsnMessage *msg, const char *type) +{ + g_return_if_fail(msg != NULL); + g_return_if_fail(type != NULL); + + if (msg->content_type != NULL) { + msg->size -= strlen(msg->content_type); + g_free(msg->content_type); + } + + msg->content_type = g_strdup(type); + + msg->size += strlen(type); +} + +const char * +msn_message_get_content_type(const MsnMessage *msg) +{ + g_return_val_if_fail(msg != NULL, NULL); + + return msg->content_type; +} + +void +msn_message_set_charset(MsnMessage *msg, const char *charset) +{ + g_return_if_fail(msg != NULL); + + if (msg->charset != NULL) { + msg->size -= strlen(msg->charset) + strlen("; charset="); + g_free(msg->charset); + } + + if (charset != NULL) { + msg->charset = g_strdup(charset); + + msg->size += strlen(charset) + strlen("; charset="); + } + else + msg->charset = NULL; +} + +const char * +msn_message_get_charset(const MsnMessage *msg) +{ + g_return_val_if_fail(msg != NULL, NULL); + + return msg->charset; +} + +void +msn_message_set_attr(MsnMessage *msg, const char *attr, const char *value) +{ + const char *temp; + char *new_attr; + + g_return_if_fail(msg != NULL); + g_return_if_fail(attr != NULL); + + temp = msn_message_get_attr(msg, attr); + + if (value == NULL) { + if (temp != NULL) { + GList *l; + + for (l = msg->attr_list; l != NULL; l = l->next) { + if (!g_ascii_strcasecmp(l->data, attr)) { + msg->attr_list = g_list_remove(msg->attr_list, l->data); + + break; + } + } + + g_hash_table_remove(msg->attr_table, attr); + + msg->size -= strlen(temp) + strlen(attr) + 4; + } + + return; + } + + new_attr = g_strdup(attr); + + g_hash_table_insert(msg->attr_table, new_attr, g_strdup(value)); + + if (temp == NULL) { + msg->attr_list = g_list_append(msg->attr_list, new_attr); + msg->size += strlen(attr) + 4; + } + else + msg->size -= strlen(temp); + + msg->size += strlen(value); +} + +const char * +msn_message_get_attr(const MsnMessage *msg, const char *attr) +{ + g_return_val_if_fail(msg != NULL, NULL); + g_return_val_if_fail(attr != NULL, NULL); + + return g_hash_table_lookup(msg->attr_table, attr); +} + +GHashTable * +msn_message_get_hashtable_from_body(const MsnMessage *msg) +{ + GHashTable *table; + char *body, *s, *c; + + g_return_val_if_fail(msg != NULL, NULL); + g_return_val_if_fail(msn_message_get_body(msg) != NULL, NULL); + + s = body = g_strdup(msn_message_get_body(msg)); + + table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + + while (*s != '\r') { + char *key, *value; + + key = s; + + GET_NEXT(s); + + value = s; + + GET_NEXT_LINE(s); + + if ((c = strchr(key, ':')) != NULL) { + *c = '\0'; + + g_hash_table_insert(table, g_strdup(key), g_strdup(value)); + } + } + + g_free(body); + + return table; +} +