Mercurial > pidgin
annotate src/protocols/yahoo/yahoo_packet.c @ 13200:33bef17125c2
[gaim-migrate @ 15563]
This is the soon-to-be-infamous nonblocking network activity patch that I've been working on. Feel free to yell at me if this makes you unhappy.
committer: Tailor Script <tailor@pidgin.im>
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Thu, 09 Feb 2006 04:17:56 +0000 |
parents | f4e58e94ced3 |
children | 4f8c85836b41 |
rev | line source |
---|---|
10392 | 1 /* |
2 * gaim | |
3 * | |
4 * Gaim is the legal property of its developers, whose names are too numerous | |
5 * to list here. Please refer to the COPYRIGHT file distributed with this | |
6 * source distribution. | |
7 * | |
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 | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
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 | |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 * | |
22 */ | |
23 | |
24 #include "internal.h" | |
25 #include "debug.h" | |
26 | |
27 #include "yahoo.h" | |
28 #include "yahoo_packet.h" | |
29 | |
30 struct yahoo_packet *yahoo_packet_new(enum yahoo_service service, enum yahoo_status status, int id) | |
31 { | |
32 struct yahoo_packet *pkt = g_new0(struct yahoo_packet, 1); | |
33 | |
34 pkt->service = service; | |
35 pkt->status = status; | |
36 pkt->id = id; | |
37 | |
38 return pkt; | |
39 } | |
40 | |
10394 | 41 void yahoo_packet_hash_str(struct yahoo_packet *pkt, int key, const char *value) |
10392 | 42 { |
43 struct yahoo_pair *pair = g_new0(struct yahoo_pair, 1); | |
44 pair->key = key; | |
45 pair->value = g_strdup(value); | |
46 pkt->hash = g_slist_append(pkt->hash, pair); | |
47 } | |
48 | |
10394 | 49 void yahoo_packet_hash_int(struct yahoo_packet *pkt, int key, int value) |
50 { | |
51 struct yahoo_pair *pair = g_new0(struct yahoo_pair, 1); | |
52 | |
53 pair->key = key; | |
54 pair->value = g_strdup_printf("%d", value); | |
55 pkt->hash = g_slist_append(pkt->hash, pair); | |
56 } | |
57 | |
58 void yahoo_packet_hash(struct yahoo_packet *pkt, const char *fmt, ...) | |
59 { | |
60 char *strval; | |
61 int key, intval; | |
62 const char *cur; | |
63 va_list ap; | |
64 | |
65 va_start(ap, fmt); | |
66 for (cur = fmt; *cur; cur++) { | |
67 key = va_arg(ap, int); | |
68 switch (*cur) { | |
69 case 'i': | |
70 intval = va_arg(ap, int); | |
71 yahoo_packet_hash_int(pkt, key, intval); | |
72 break; | |
73 case 's': | |
74 strval = va_arg(ap, char *); | |
75 yahoo_packet_hash_str(pkt, key, strval); | |
76 break; | |
77 default: | |
78 gaim_debug_error("yahoo", "Invalid format character '%c'\n", *cur); | |
79 break; | |
80 } | |
81 } | |
82 va_end(ap); | |
83 } | |
84 | |
10392 | 85 int yahoo_packet_length(struct yahoo_packet *pkt) |
86 { | |
87 GSList *l; | |
88 | |
89 int len = 0; | |
90 | |
91 l = pkt->hash; | |
92 while (l) { | |
93 struct yahoo_pair *pair = l->data; | |
94 int tmp = pair->key; | |
95 do { | |
96 tmp /= 10; | |
97 len++; | |
98 } while (tmp); | |
99 len += 2; | |
100 len += strlen(pair->value); | |
101 len += 2; | |
102 l = l->next; | |
103 } | |
104 | |
105 return len; | |
106 } | |
107 | |
108 void yahoo_packet_read(struct yahoo_packet *pkt, guchar *data, int len) | |
109 { | |
110 int pos = 0; | |
111 | |
112 while (pos + 1 < len) { | |
113 char key[64], *value = NULL, *esc; | |
114 int accept; | |
115 int x; | |
116 | |
117 struct yahoo_pair *pair = g_new0(struct yahoo_pair, 1); | |
118 | |
119 /* this is weird, and in one of the chat packets, and causes us | |
120 * think all the values are keys and all the keys are values after | |
121 * this point if we don't handle it */ | |
122 if (data[pos] == '\0') { | |
123 while (pos + 1 < len) { | |
124 if (data[pos] == 0xc0 && data[pos + 1] == 0x80) | |
125 break; | |
126 pos++; | |
127 } | |
128 pos += 2; | |
129 g_free(pair); | |
130 continue; | |
131 } | |
132 | |
133 x = 0; | |
134 while (pos + 1 < len) { | |
135 if (data[pos] == 0xc0 && data[pos + 1] == 0x80) | |
136 break; | |
137 if (x >= sizeof(key)-1) { | |
138 x++; | |
139 pos++; | |
140 continue; | |
141 } | |
142 key[x++] = data[pos++]; | |
143 } | |
144 if (x >= sizeof(key)-1) { | |
145 x = 0; | |
146 } | |
147 key[x] = 0; | |
148 pos += 2; | |
149 pair->key = strtol(key, NULL, 10); | |
150 accept = x; /* if x is 0 there was no key, so don't accept it */ | |
151 | |
152 if (len - pos + 1 <= 0) { | |
153 /* Truncated. Garbage or something. */ | |
154 accept = 0; | |
155 } | |
156 | |
157 if (accept) { | |
158 value = g_malloc(len - pos + 1); | |
159 x = 0; | |
160 while (pos + 1 < len) { | |
161 if (data[pos] == 0xc0 && data[pos + 1] == 0x80) | |
162 break; | |
163 value[x++] = data[pos++]; | |
164 } | |
165 value[x] = 0; | |
166 pair->value = g_strdup(value); | |
167 g_free(value); | |
168 pkt->hash = g_slist_append(pkt->hash, pair); | |
169 esc = g_strescape(pair->value, NULL); | |
170 gaim_debug(GAIM_DEBUG_MISC, "yahoo", | |
171 "Key: %d \tValue: %s\n", pair->key, esc); | |
172 g_free(esc); | |
173 } else { | |
174 g_free(pair); | |
175 } | |
176 pos += 2; | |
177 | |
178 /* Skip over garbage we've noticed in the mail notifications */ | |
179 if (data[0] == '9' && data[pos] == 0x01) | |
180 pos++; | |
181 } | |
182 } | |
183 | |
184 void yahoo_packet_write(struct yahoo_packet *pkt, guchar *data) | |
185 { | |
186 GSList *l = pkt->hash; | |
187 int pos = 0; | |
188 | |
189 while (l) { | |
190 struct yahoo_pair *pair = l->data; | |
11161 | 191 gchar buf[100]; |
10392 | 192 |
193 g_snprintf(buf, sizeof(buf), "%d", pair->key); | |
11161 | 194 strcpy((char *)&data[pos], buf); |
10392 | 195 pos += strlen(buf); |
196 data[pos++] = 0xc0; | |
197 data[pos++] = 0x80; | |
198 | |
11161 | 199 strcpy((char *)&data[pos], pair->value); |
10392 | 200 pos += strlen(pair->value); |
201 data[pos++] = 0xc0; | |
202 data[pos++] = 0x80; | |
203 | |
204 l = l->next; | |
205 } | |
206 } | |
207 | |
208 void yahoo_packet_dump(guchar *data, int len) | |
209 { | |
210 #ifdef YAHOO_DEBUG | |
211 int i; | |
212 | |
213 gaim_debug(GAIM_DEBUG_MISC, "yahoo", ""); | |
214 | |
215 for (i = 0; i + 1 < len; i += 2) { | |
216 if ((i % 16 == 0) && i) { | |
217 gaim_debug(GAIM_DEBUG_MISC, NULL, "\n"); | |
218 gaim_debug(GAIM_DEBUG_MISC, "yahoo", ""); | |
219 } | |
220 | |
221 gaim_debug(GAIM_DEBUG_MISC, NULL, "%02x%02x ", data[i], data[i + 1]); | |
222 } | |
223 if (i < len) | |
224 gaim_debug(GAIM_DEBUG_MISC, NULL, "%02x", data[i]); | |
225 | |
226 gaim_debug(GAIM_DEBUG_MISC, NULL, "\n"); | |
227 gaim_debug(GAIM_DEBUG_MISC, "yahoo", ""); | |
228 | |
229 for (i = 0; i < len; i++) { | |
230 if ((i % 16 == 0) && i) { | |
231 gaim_debug(GAIM_DEBUG_MISC, NULL, "\n"); | |
232 gaim_debug(GAIM_DEBUG_MISC, "yahoo", ""); | |
233 } | |
234 | |
235 if (g_ascii_isprint(data[i])) | |
236 gaim_debug(GAIM_DEBUG_MISC, NULL, "%c ", data[i]); | |
237 else | |
238 gaim_debug(GAIM_DEBUG_MISC, NULL, ". "); | |
239 } | |
240 | |
241 gaim_debug(GAIM_DEBUG_MISC, NULL, "\n"); | |
242 #endif | |
243 } | |
244 | |
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
245 static void |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
246 yahoo_packet_send_can_write(gpointer data, gint source, GaimInputCondition cond) |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
247 { |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
248 struct yahoo_data *yd = data; |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
249 int ret, writelen; |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
250 |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
251 writelen = gaim_circ_buffer_get_max_read(yd->txbuf); |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
252 |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
253 if (writelen == 0) { |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
254 gaim_input_remove(yd->txhandler); |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
255 yd->txhandler = -1; |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
256 return; |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
257 } |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
258 |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
259 ret = write(yd->fd, yd->txbuf->outptr, writelen); |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
260 |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
261 if (ret < 0 && errno == EAGAIN) |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
262 return; |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
263 else if (ret < 0) { |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
264 /* TODO: what to do here - do we really have to disconnect? */ |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
265 gaim_connection_error(yd->gc, _("Write Error")); |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
266 return; |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
267 } |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
268 |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
269 gaim_circ_buffer_mark_read(yd->txbuf, ret); |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
270 } |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
271 |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
272 |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
273 gsize yahoo_packet_build(struct yahoo_packet *pkt, int pad, gboolean wm, |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
274 guchar **buf) |
10392 | 275 { |
276 int pktlen = yahoo_packet_length(pkt); | |
277 int len = YAHOO_PACKET_HDRLEN + pktlen; | |
278 guchar *data; | |
279 int pos = 0; | |
280 | |
281 data = g_malloc0(len + 1); | |
282 | |
283 memcpy(data + pos, "YMSG", 4); pos += 4; | |
284 | |
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
285 if (wm) |
10392 | 286 pos += yahoo_put16(data + pos, YAHOO_WEBMESSENGER_PROTO_VER); |
287 else | |
288 pos += yahoo_put16(data + pos, YAHOO_PROTO_VER); | |
289 pos += yahoo_put16(data + pos, 0x0000); | |
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
290 pos += yahoo_put16(data + pos, pktlen + pad); |
10392 | 291 pos += yahoo_put16(data + pos, pkt->service); |
292 pos += yahoo_put32(data + pos, pkt->status); | |
293 pos += yahoo_put32(data + pos, pkt->id); | |
294 | |
295 yahoo_packet_write(pkt, data + pos); | |
296 | |
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
297 *buf = data; |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
298 |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
299 return len; |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
300 } |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
301 |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
302 int yahoo_packet_send(struct yahoo_packet *pkt, struct yahoo_data *yd) |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
303 { |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
304 gsize len; |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
305 int ret; |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
306 guchar *data; |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
307 |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
308 if (yd->fd < 0) |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
309 return -1; |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
310 |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
311 len = yahoo_packet_build(pkt, 0, yd->wm, &data); |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
312 |
10392 | 313 yahoo_packet_dump(data, len); |
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
314 if (yd->txhandler == -1) |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
315 ret = write(yd->fd, data, len); |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
316 else { |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
317 ret = -1; |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
318 errno = EAGAIN; |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
319 } |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
320 |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
321 if (ret < 0 && errno == EAGAIN) |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
322 ret = 0; |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
323 else if (ret <= 0) { |
10392 | 324 gaim_debug_warning("yahoo", "Only wrote %d of %d bytes!", ret, len); |
13200
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
325 g_free(data); |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
326 return ret; |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
327 } |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
328 |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
329 if (ret < len) { |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
330 if (yd->txhandler == -1) |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
331 yd->txhandler = gaim_input_add(yd->fd, GAIM_INPUT_WRITE, |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
332 yahoo_packet_send_can_write, yd); |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
333 gaim_circ_buffer_append(yd->txbuf, data + ret, len - ret); |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
334 } |
33bef17125c2
[gaim-migrate @ 15563]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11644
diff
changeset
|
335 |
10392 | 336 g_free(data); |
337 | |
338 return ret; | |
339 } | |
340 | |
341 int yahoo_packet_send_and_free(struct yahoo_packet *pkt, struct yahoo_data *yd) | |
342 { | |
343 int ret; | |
11644 | 344 |
10392 | 345 ret = yahoo_packet_send(pkt, yd); |
346 yahoo_packet_free(pkt); | |
347 return ret; | |
348 } | |
349 | |
350 void yahoo_packet_free(struct yahoo_packet *pkt) | |
351 { | |
352 while (pkt->hash) { | |
353 struct yahoo_pair *pair = pkt->hash->data; | |
354 g_free(pair->value); | |
355 g_free(pair); | |
356 pkt->hash = g_slist_remove(pkt->hash, pair); | |
357 } | |
358 g_free(pkt); | |
359 } |