Mercurial > pidgin.yaz
annotate src/protocols/gg/lib/pubdir50.c @ 13023:e8adf8183cf4
[gaim-migrate @ 15376]
A few tweaks. Don't show connection errors in the buddy list.
Anything else for beta2? I'll tag and make tarballs tonight around
11:30 EST, if not.
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Mon, 23 Jan 2006 23:16:31 +0000 |
parents | 188d7e79166b |
children |
rev | line source |
---|---|
12372
188d7e79166b
[gaim-migrate @ 14676]
Richard Laager <rlaager@wiktel.com>
parents:
11360
diff
changeset
|
1 /* $Id: pubdir50.c 14676 2005-12-06 19:22:13Z rlaager $ */ |
11360 | 2 |
3 /* | |
4 * (C) Copyright 2003 Wojtek Kaniewski <wojtekka@irc.pl> | |
5 * | |
6 * This program is free software; you can redistribute it and/or modify | |
7 * it under the terms of the GNU Lesser General Public License Version | |
8 * 2.1 as published by the Free Software Foundation. | |
9 * | |
10 * This program is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 * GNU Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this program; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, | |
18 * USA. | |
19 */ | |
20 | |
21 #include <errno.h> | |
22 #include <stdlib.h> | |
23 #include <string.h> | |
24 #include <time.h> | |
25 | |
26 #include "libgadu.h" | |
27 | |
28 /* | |
29 * gg_pubdir50_new() | |
30 * | |
31 * tworzy nową zmienną typu gg_pubdir50_t. | |
32 * | |
33 * zaalokowana zmienna lub NULL w przypadku braku pamięci. | |
34 */ | |
35 gg_pubdir50_t gg_pubdir50_new(int type) | |
36 { | |
37 gg_pubdir50_t res = malloc(sizeof(struct gg_pubdir50_s)); | |
38 | |
39 gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_new(%d);\n", type); | |
40 | |
41 if (!res) { | |
42 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_new() out of memory\n"); | |
43 return NULL; | |
44 } | |
45 | |
46 memset(res, 0, sizeof(struct gg_pubdir50_s)); | |
47 | |
48 res->type = type; | |
49 | |
50 return res; | |
51 } | |
52 | |
53 /* | |
54 * gg_pubdir50_add_n() // funkcja wewnętrzna | |
55 * | |
56 * funkcja dodaje lub zastępuje istniejące pole do zapytania lub odpowiedzi. | |
57 * | |
58 * - req - wskaźnik opisu zapytania, | |
59 * - num - numer wyniku (0 dla zapytania), | |
60 * - field - nazwa pola, | |
61 * - value - wartość pola, | |
62 * | |
63 * 0/-1 | |
64 */ | |
12372
188d7e79166b
[gaim-migrate @ 14676]
Richard Laager <rlaager@wiktel.com>
parents:
11360
diff
changeset
|
65 static int gg_pubdir50_add_n(gg_pubdir50_t req, int num, const char *field, const char *value) |
11360 | 66 { |
67 struct gg_pubdir50_entry *tmp = NULL, *entry; | |
68 char *dupfield, *dupvalue; | |
69 int i; | |
70 | |
71 gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_add_n(%p, %d, \"%s\", \"%s\");\n", req, num, field, value); | |
72 | |
73 if (!(dupvalue = strdup(value))) { | |
74 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_add_n() out of memory\n"); | |
75 return -1; | |
76 } | |
77 | |
78 for (i = 0; i < req->entries_count; i++) { | |
79 if (req->entries[i].num != num || strcmp(req->entries[i].field, field)) | |
80 continue; | |
81 | |
82 free(req->entries[i].value); | |
83 req->entries[i].value = dupvalue; | |
84 | |
85 return 0; | |
86 } | |
87 | |
88 if (!(dupfield = strdup(field))) { | |
89 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_add_n() out of memory\n"); | |
90 free(dupvalue); | |
91 return -1; | |
92 } | |
93 | |
94 if (!(tmp = realloc(req->entries, sizeof(struct gg_pubdir50_entry) * (req->entries_count + 1)))) { | |
95 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_add_n() out of memory\n"); | |
96 free(dupfield); | |
97 free(dupvalue); | |
98 return -1; | |
99 } | |
100 | |
101 req->entries = tmp; | |
102 | |
103 entry = &req->entries[req->entries_count]; | |
104 entry->num = num; | |
105 entry->field = dupfield; | |
106 entry->value = dupvalue; | |
107 | |
108 req->entries_count++; | |
109 | |
110 return 0; | |
111 } | |
112 | |
113 /* | |
114 * gg_pubdir50_add() | |
115 * | |
116 * funkcja dodaje pole do zapytania. | |
117 * | |
118 * - req - wskaźnik opisu zapytania, | |
119 * - field - nazwa pola, | |
120 * - value - wartość pola, | |
121 * | |
122 * 0/-1 | |
123 */ | |
124 int gg_pubdir50_add(gg_pubdir50_t req, const char *field, const char *value) | |
125 { | |
126 return gg_pubdir50_add_n(req, 0, field, value); | |
127 } | |
128 | |
129 /* | |
130 * gg_pubdir50_seq_set() | |
131 * | |
132 * ustawia numer sekwencyjny zapytania. | |
133 * | |
134 * - req - zapytanie, | |
135 * - seq - nowy numer sekwencyjny. | |
136 * | |
137 * 0/-1. | |
138 */ | |
139 int gg_pubdir50_seq_set(gg_pubdir50_t req, uint32_t seq) | |
140 { | |
141 gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_seq_set(%p, %d);\n", req, seq); | |
142 | |
143 if (!req) { | |
144 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_seq_set() invalid arguments\n"); | |
145 errno = EFAULT; | |
146 return -1; | |
147 } | |
148 | |
149 req->seq = seq; | |
150 | |
151 return 0; | |
152 } | |
153 | |
154 /* | |
155 * gg_pubdir50_free() | |
156 * | |
157 * zwalnia pamięć po zapytaniu lub rezultacie szukania użytkownika. | |
158 * | |
159 * - s - zwalniana zmienna, | |
160 */ | |
161 void gg_pubdir50_free(gg_pubdir50_t s) | |
162 { | |
163 int i; | |
164 | |
165 if (!s) | |
166 return; | |
167 | |
168 for (i = 0; i < s->entries_count; i++) { | |
169 free(s->entries[i].field); | |
170 free(s->entries[i].value); | |
171 } | |
172 | |
173 free(s->entries); | |
174 free(s); | |
175 } | |
176 | |
177 /* | |
178 * gg_pubdir50() | |
179 * | |
180 * wysyła zapytanie katalogu publicznego do serwera. | |
181 * | |
182 * - sess - sesja, | |
183 * - req - zapytanie. | |
184 * | |
185 * numer sekwencyjny wyszukiwania lub 0 w przypadku błędu. | |
186 */ | |
187 uint32_t gg_pubdir50(struct gg_session *sess, gg_pubdir50_t req) | |
188 { | |
189 int i, size = 5; | |
190 uint32_t res; | |
191 char *buf, *p; | |
192 struct gg_pubdir50_request *r; | |
193 | |
194 gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50(%p, %p);\n", sess, req); | |
195 | |
196 if (!sess || !req) { | |
197 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50() invalid arguments\n"); | |
198 errno = EFAULT; | |
199 return 0; | |
200 } | |
201 | |
202 if (sess->state != GG_STATE_CONNECTED) { | |
203 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50() not connected\n"); | |
204 errno = ENOTCONN; | |
205 return 0; | |
206 } | |
207 | |
208 for (i = 0; i < req->entries_count; i++) { | |
209 /* wyszukiwanie bierze tylko pierwszy wpis */ | |
210 if (req->entries[i].num) | |
211 continue; | |
212 | |
213 size += strlen(req->entries[i].field) + 1; | |
214 size += strlen(req->entries[i].value) + 1; | |
215 } | |
216 | |
217 if (!(buf = malloc(size))) { | |
218 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50() out of memory (%d bytes)\n", size); | |
219 return 0; | |
220 } | |
221 | |
222 r = (struct gg_pubdir50_request*) buf; | |
223 res = time(NULL); | |
224 r->type = req->type; | |
225 r->seq = (req->seq) ? gg_fix32(req->seq) : gg_fix32(time(NULL)); | |
226 req->seq = gg_fix32(r->seq); | |
227 | |
228 for (i = 0, p = buf + 5; i < req->entries_count; i++) { | |
229 if (req->entries[i].num) | |
230 continue; | |
231 | |
232 strcpy(p, req->entries[i].field); | |
233 p += strlen(p) + 1; | |
234 | |
235 strcpy(p, req->entries[i].value); | |
236 p += strlen(p) + 1; | |
237 } | |
238 | |
239 if (gg_send_packet(sess, GG_PUBDIR50_REQUEST, buf, size, NULL, 0) == -1) | |
240 res = 0; | |
241 | |
242 free(buf); | |
243 | |
244 return res; | |
245 } | |
246 | |
247 /* | |
248 * gg_pubdir50_handle_reply() // funkcja wewnętrzna | |
249 * | |
250 * analizuje przychodzący pakiet odpowiedzi i zapisuje wynik w struct gg_event. | |
251 * | |
252 * - e - opis zdarzenia | |
253 * - packet - zawartość pakietu odpowiedzi | |
254 * - length - długość pakietu odpowiedzi | |
255 * | |
256 * 0/-1 | |
257 */ | |
258 int gg_pubdir50_handle_reply(struct gg_event *e, const char *packet, int length) | |
259 { | |
260 const char *end = packet + length, *p; | |
261 struct gg_pubdir50_reply *r = (struct gg_pubdir50_reply*) packet; | |
262 gg_pubdir50_t res; | |
263 int num = 0; | |
264 | |
265 gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_handle_reply(%p, %p, %d);\n", e, packet, length); | |
266 | |
267 if (!e || !packet) { | |
268 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_handle_reply() invalid arguments\n"); | |
269 errno = EFAULT; | |
270 return -1; | |
271 } | |
272 | |
273 if (length < 5) { | |
274 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_handle_reply() packet too short\n"); | |
275 errno = EINVAL; | |
276 return -1; | |
277 } | |
278 | |
279 if (!(res = gg_pubdir50_new(r->type))) { | |
280 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_handle_reply() unable to allocate reply\n"); | |
281 return -1; | |
282 } | |
283 | |
284 e->event.pubdir50 = res; | |
285 | |
286 res->seq = gg_fix32(r->seq); | |
287 | |
288 switch (res->type) { | |
289 case GG_PUBDIR50_READ: | |
290 e->type = GG_EVENT_PUBDIR50_READ; | |
291 break; | |
292 | |
293 case GG_PUBDIR50_WRITE: | |
294 e->type = GG_EVENT_PUBDIR50_WRITE; | |
295 break; | |
296 | |
297 default: | |
298 e->type = GG_EVENT_PUBDIR50_SEARCH_REPLY; | |
299 break; | |
300 } | |
301 | |
302 /* brak wyników? */ | |
303 if (length == 5) | |
304 return 0; | |
305 | |
306 /* pomiń początek odpowiedzi */ | |
307 p = packet + 5; | |
308 | |
309 while (p < end) { | |
310 const char *field, *value; | |
311 | |
312 field = p; | |
313 | |
314 /* sprawdź, czy nie mamy podziału na kolejne pole */ | |
315 if (!*field) { | |
316 num++; | |
317 field++; | |
318 } | |
319 | |
320 value = NULL; | |
321 | |
322 for (p = field; p < end; p++) { | |
323 /* jeśli mamy koniec tekstu... */ | |
324 if (!*p) { | |
325 /* ...i jeszcze nie mieliśmy wartości pola to | |
326 * wiemy, że po tym zerze jest wartość... */ | |
327 if (!value) | |
328 value = p + 1; | |
329 else | |
330 /* ...w przeciwym wypadku koniec | |
331 * wartości i możemy wychodzić | |
332 * grzecznie z pętli */ | |
333 break; | |
334 } | |
335 } | |
336 | |
337 /* sprawdźmy, czy pole nie wychodzi poza pakiet, żeby nie | |
338 * mieć segfaultów, jeśli serwer przestanie zakańczać pakietów | |
339 * przez \0 */ | |
340 | |
341 if (p == end) { | |
342 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_handle_reply() premature end of packet\n"); | |
343 goto failure; | |
344 } | |
345 | |
346 p++; | |
347 | |
348 /* jeśli dostaliśmy namier na następne wyniki, to znaczy że | |
349 * mamy koniec wyników i nie jest to kolejna osoba. */ | |
350 if (!strcasecmp(field, "nextstart")) { | |
351 res->next = atoi(value); | |
352 num--; | |
353 } else { | |
354 if (gg_pubdir50_add_n(res, num, field, value) == -1) | |
355 goto failure; | |
356 } | |
357 } | |
358 | |
359 res->count = num + 1; | |
360 | |
361 return 0; | |
362 | |
363 failure: | |
364 gg_pubdir50_free(res); | |
365 return -1; | |
366 } | |
367 | |
368 /* | |
369 * gg_pubdir50_get() | |
370 * | |
371 * pobiera informację z rezultatu wyszukiwania. | |
372 * | |
373 * - res - rezultat wyszukiwania, | |
374 * - num - numer odpowiedzi, | |
375 * - field - nazwa pola (wielkość liter nie ma znaczenia). | |
376 * | |
377 * wartość pola lub NULL, jeśli nie znaleziono. | |
378 */ | |
379 const char *gg_pubdir50_get(gg_pubdir50_t res, int num, const char *field) | |
380 { | |
381 char *value = NULL; | |
382 int i; | |
383 | |
384 gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_get(%p, %d, \"%s\");\n", res, num, field); | |
385 | |
386 if (!res || num < 0 || !field) { | |
387 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_get() invalid arguments\n"); | |
388 errno = EINVAL; | |
389 return NULL; | |
390 } | |
391 | |
392 for (i = 0; i < res->entries_count; i++) { | |
393 if (res->entries[i].num == num && !strcasecmp(res->entries[i].field, field)) { | |
394 value = res->entries[i].value; | |
395 break; | |
396 } | |
397 } | |
398 | |
399 return value; | |
400 } | |
401 | |
402 /* | |
403 * gg_pubdir50_count() | |
404 * | |
405 * zwraca ilość wyników danego zapytania. | |
406 * | |
407 * - res - odpowiedź | |
408 * | |
409 * ilość lub -1 w przypadku błędu. | |
410 */ | |
411 int gg_pubdir50_count(gg_pubdir50_t res) | |
412 { | |
413 return (!res) ? -1 : res->count; | |
414 } | |
415 | |
416 /* | |
417 * gg_pubdir50_type() | |
418 * | |
419 * zwraca rodzaj zapytania lub odpowiedzi. | |
420 * | |
421 * - res - zapytanie lub odpowiedź | |
422 * | |
423 * ilość lub -1 w przypadku błędu. | |
424 */ | |
425 int gg_pubdir50_type(gg_pubdir50_t res) | |
426 { | |
427 return (!res) ? -1 : res->type; | |
428 } | |
429 | |
430 /* | |
431 * gg_pubdir50_next() | |
432 * | |
433 * zwraca numer, od którego należy rozpocząć kolejne wyszukiwanie, jeśli | |
434 * zależy nam na kolejnych wynikach. | |
435 * | |
436 * - res - odpowiedź | |
437 * | |
438 * numer lub -1 w przypadku błędu. | |
439 */ | |
440 uin_t gg_pubdir50_next(gg_pubdir50_t res) | |
441 { | |
442 return (!res) ? (unsigned) -1 : res->next; | |
443 } | |
444 | |
445 /* | |
446 * gg_pubdir50_seq() | |
447 * | |
448 * zwraca numer sekwencyjny zapytania lub odpowiedzi. | |
449 * | |
450 * - res - zapytanie lub odpowiedź | |
451 * | |
452 * numer lub -1 w przypadku błędu. | |
453 */ | |
454 uint32_t gg_pubdir50_seq(gg_pubdir50_t res) | |
455 { | |
456 return (!res) ? (unsigned) -1 : res->seq; | |
457 } | |
458 | |
459 /* | |
460 * Local variables: | |
461 * c-indentation-style: k&r | |
462 * c-basic-offset: 8 | |
463 * indent-tabs-mode: notnil | |
464 * End: | |
465 * | |
466 * vim: shiftwidth=8: | |
467 */ |