Mercurial > pidgin.yaz
diff src/protocols/yahoo/yahoo_packet.c @ 10392:a8f9e5ce4f92
[gaim-migrate @ 11620]
a little bit of clean up and reorganization of the yahoo prpl.
I moved the packet functions to their own file, renamed a couple of them,
added a convience function and used it a lot. I plan on adding several
more convience functions.
committer: Tailor Script <tailor@pidgin.im>
author | Tim Ringenbach <marv@pidgin.im> |
---|---|
date | Thu, 16 Dec 2004 21:47:54 +0000 |
parents | |
children | 45a0a07e8b25 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/yahoo/yahoo_packet.c Thu Dec 16 21:47:54 2004 +0000 @@ -0,0 +1,297 @@ +/* + * gaim + * + * Gaim is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 "internal.h" +#include "debug.h" + +#include "yahoo.h" +#include "yahoo_packet.h" + +struct yahoo_packet *yahoo_packet_new(enum yahoo_service service, enum yahoo_status status, int id) +{ + struct yahoo_packet *pkt = g_new0(struct yahoo_packet, 1); + + pkt->service = service; + pkt->status = status; + pkt->id = id; + + return pkt; +} + +void yahoo_packet_hash(struct yahoo_packet *pkt, int key, const char *value) +{ + struct yahoo_pair *pair = g_new0(struct yahoo_pair, 1); + pair->key = key; + pair->value = g_strdup(value); + pkt->hash = g_slist_append(pkt->hash, pair); +} + +int yahoo_packet_length(struct yahoo_packet *pkt) +{ + GSList *l; + + int len = 0; + + l = pkt->hash; + while (l) { + struct yahoo_pair *pair = l->data; + int tmp = pair->key; + do { + tmp /= 10; + len++; + } while (tmp); + len += 2; + len += strlen(pair->value); + len += 2; + l = l->next; + } + + return len; +} + +void yahoo_packet_read(struct yahoo_packet *pkt, guchar *data, int len) +{ + int pos = 0; + + while (pos + 1 < len) { + char key[64], *value = NULL, *esc; + int accept; + int x; + + struct yahoo_pair *pair = g_new0(struct yahoo_pair, 1); + + /* this is weird, and in one of the chat packets, and causes us + * think all the values are keys and all the keys are values after + * this point if we don't handle it */ + if (data[pos] == '\0') { + while (pos + 1 < len) { + if (data[pos] == 0xc0 && data[pos + 1] == 0x80) + break; + pos++; + } + pos += 2; + g_free(pair); + continue; + } + + x = 0; + while (pos + 1 < len) { + if (data[pos] == 0xc0 && data[pos + 1] == 0x80) + break; + if (x >= sizeof(key)-1) { + x++; + pos++; + continue; + } + key[x++] = data[pos++]; + } + if (x >= sizeof(key)-1) { + x = 0; + } + key[x] = 0; + pos += 2; + pair->key = strtol(key, NULL, 10); + accept = x; /* if x is 0 there was no key, so don't accept it */ + + if (len - pos + 1 <= 0) { + /* Truncated. Garbage or something. */ + accept = 0; + } + + if (accept) { + value = g_malloc(len - pos + 1); + x = 0; + while (pos + 1 < len) { + if (data[pos] == 0xc0 && data[pos + 1] == 0x80) + break; + value[x++] = data[pos++]; + } + value[x] = 0; + pair->value = g_strdup(value); + g_free(value); + pkt->hash = g_slist_append(pkt->hash, pair); + esc = g_strescape(pair->value, NULL); + gaim_debug(GAIM_DEBUG_MISC, "yahoo", + "Key: %d \tValue: %s\n", pair->key, esc); + g_free(esc); + } else { + g_free(pair); + } + pos += 2; + + /* Skip over garbage we've noticed in the mail notifications */ + if (data[0] == '9' && data[pos] == 0x01) + pos++; + } +} + +void yahoo_packet_write(struct yahoo_packet *pkt, guchar *data) +{ + GSList *l = pkt->hash; + int pos = 0; + + while (l) { + struct yahoo_pair *pair = l->data; + guchar buf[100]; + + g_snprintf(buf, sizeof(buf), "%d", pair->key); + strcpy(data + pos, buf); + pos += strlen(buf); + data[pos++] = 0xc0; + data[pos++] = 0x80; + + strcpy(data + pos, pair->value); + pos += strlen(pair->value); + data[pos++] = 0xc0; + data[pos++] = 0x80; + + l = l->next; + } +} + +void yahoo_packet_dump(guchar *data, int len) +{ +#ifdef YAHOO_DEBUG + int i; + + gaim_debug(GAIM_DEBUG_MISC, "yahoo", ""); + + for (i = 0; i + 1 < len; i += 2) { + if ((i % 16 == 0) && i) { + gaim_debug(GAIM_DEBUG_MISC, NULL, "\n"); + gaim_debug(GAIM_DEBUG_MISC, "yahoo", ""); + } + + gaim_debug(GAIM_DEBUG_MISC, NULL, "%02x%02x ", data[i], data[i + 1]); + } + if (i < len) + gaim_debug(GAIM_DEBUG_MISC, NULL, "%02x", data[i]); + + gaim_debug(GAIM_DEBUG_MISC, NULL, "\n"); + gaim_debug(GAIM_DEBUG_MISC, "yahoo", ""); + + for (i = 0; i < len; i++) { + if ((i % 16 == 0) && i) { + gaim_debug(GAIM_DEBUG_MISC, NULL, "\n"); + gaim_debug(GAIM_DEBUG_MISC, "yahoo", ""); + } + + if (g_ascii_isprint(data[i])) + gaim_debug(GAIM_DEBUG_MISC, NULL, "%c ", data[i]); + else + gaim_debug(GAIM_DEBUG_MISC, NULL, ". "); + } + + gaim_debug(GAIM_DEBUG_MISC, NULL, "\n"); +#endif +} + +int yahoo_packet_send(struct yahoo_packet *pkt, struct yahoo_data *yd) +{ + int pktlen = yahoo_packet_length(pkt); + int len = YAHOO_PACKET_HDRLEN + pktlen; + int ret; + + guchar *data; + int pos = 0; + + if (yd->fd < 0) + return -1; + + data = g_malloc0(len + 1); + + memcpy(data + pos, "YMSG", 4); pos += 4; + + if (yd->wm) + pos += yahoo_put16(data + pos, YAHOO_WEBMESSENGER_PROTO_VER); + else + pos += yahoo_put16(data + pos, YAHOO_PROTO_VER); + + pos += yahoo_put16(data + pos, 0x0000); + pos += yahoo_put16(data + pos, pktlen); + pos += yahoo_put16(data + pos, pkt->service); + pos += yahoo_put32(data + pos, pkt->status); + pos += yahoo_put32(data + pos, pkt->id); + + yahoo_packet_write(pkt, data + pos); + + yahoo_packet_dump(data, len); + ret = write(yd->fd, data, len); + if (ret != len) + gaim_debug_warning("yahoo", "Only wrote %d of %d bytes!", ret, len); + g_free(data); + + return ret; +} + +int yahoo_packet_send_and_free(struct yahoo_packet *pkt, struct yahoo_data *yd) +{ + int ret; + + ret = yahoo_packet_send(pkt, yd); + yahoo_packet_free(pkt); + return ret; +} + +int yahoo_packet_send_special(struct yahoo_packet *pkt, int fd, int pad) +{ + int pktlen = yahoo_packet_length(pkt); + int len = YAHOO_PACKET_HDRLEN + pktlen; + int ret; + + guchar *data; + int pos = 0; + + if (fd < 0) + return -1; + + data = g_malloc0(len + 1); + + memcpy(data + pos, "YMSG", 4); pos += 4; + + pos += yahoo_put16(data + pos, YAHOO_PROTO_VER); + + pos += yahoo_put16(data + pos, 0x0000); + pos += yahoo_put16(data + pos, pktlen + pad); + pos += yahoo_put16(data + pos, pkt->service); + pos += yahoo_put32(data + pos, pkt->status); + pos += yahoo_put32(data + pos, pkt->id); + + yahoo_packet_write(pkt, data + pos); + + ret = write(fd, data, len); + g_free(data); + + return ret; +} + +void yahoo_packet_free(struct yahoo_packet *pkt) +{ + while (pkt->hash) { + struct yahoo_pair *pair = pkt->hash->data; + g_free(pair->value); + g_free(pair); + pkt->hash = g_slist_remove(pkt->hash, pair); + } + g_free(pkt); +}