connwrap - initialize gnutls session in cw_connect
[centerim.git] / libgadu / pubdir50.c
blob4bc501e0ad4a3726b48664c7d50cf1d4d48e03ad
1 /* $Id: pubdir50.c,v 1.1 2004/01/26 23:49:54 konst Exp $ */
3 /*
4 * (C) Copyright 2003 Wojtek Kaniewski <wojtekka@irc.pl>
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.
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.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <errno.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <time.h>
25 #include "libgadu.h"
28 * gg_pubdir50_new()
30 * tworzy now± zmienn± typu gg_pubdir50_t.
32 * zaalokowana zmienna lub NULL w przypadku braku pamiêci.
34 gg_pubdir50_t gg_pubdir50_new(int type)
36 gg_pubdir50_t res = malloc(sizeof(struct gg_pubdir50_s));
38 gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_new(%d);\n", type);
40 if (!res) {
41 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_new() out of memory\n");
42 return NULL;
45 memset(res, 0, sizeof(struct gg_pubdir50_s));
47 res->type = type;
49 return res;
53 * gg_pubdir50_add_n() // funkcja wewnêtrzna
55 * funkcja dodaje lub zastêpuje istniej±ce pole do zapytania lub odpowiedzi.
57 * - req - wska¼nik opisu zapytania,
58 * - num - numer wyniku (0 dla zapytania),
59 * - field - nazwa pola,
60 * - value - warto¶æ pola,
62 * 0/-1
64 int gg_pubdir50_add_n(gg_pubdir50_t req, int num, const char *field, const char *value)
66 struct gg_pubdir50_entry *tmp = NULL, *entry;
67 char *dupfield, *dupvalue;
68 int i;
70 gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_add_n(%p, %d, \"%s\", \"%s\");\n", req, num, field, value);
72 if (!(dupvalue = strdup(value))) {
73 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_add_n() out of memory\n");
74 return -1;
77 for (i = 0; i < req->entries_count; i++) {
78 if (req->entries[i].num != num || strcmp(req->entries[i].field, field))
79 continue;
81 free(req->entries[i].value);
82 req->entries[i].value = dupvalue;
84 return 0;
87 if (!(dupfield = strdup(field))) {
88 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_add_n() out of memory\n");
89 free(dupvalue);
90 return -1;
93 if (!(tmp = realloc(req->entries, sizeof(struct gg_pubdir50_entry) * (req->entries_count + 1)))) {
94 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_add_n() out of memory\n");
95 free(dupfield);
96 free(dupvalue);
97 return -1;
100 req->entries = tmp;
102 entry = &req->entries[req->entries_count];
103 entry->num = num;
104 entry->field = dupfield;
105 entry->value = dupvalue;
107 req->entries_count++;
109 return 0;
113 * gg_pubdir50_add()
115 * funkcja dodaje pole do zapytania.
117 * - req - wska¼nik opisu zapytania,
118 * - field - nazwa pola,
119 * - value - warto¶æ pola,
121 * 0/-1
123 int gg_pubdir50_add(gg_pubdir50_t req, const char *field, const char *value)
125 return gg_pubdir50_add_n(req, 0, field, value);
129 * gg_pubdir50_seq_set()
131 * ustawia numer sekwencyjny zapytania.
133 * - req - zapytanie,
134 * - seq - nowy numer sekwencyjny.
136 * 0/-1.
138 int gg_pubdir50_seq_set(gg_pubdir50_t req, uint32_t seq)
140 gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_seq_set(%p, %d);\n", req, seq);
142 if (!req) {
143 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_seq_set() invalid arguments\n");
144 errno = EFAULT;
145 return -1;
148 req->seq = seq;
150 return 0;
154 * gg_pubdir50_free()
156 * zwalnia pamiêæ po zapytaniu lub rezultacie szukania u¿ytkownika.
158 * - s - zwalniana zmienna,
160 void gg_pubdir50_free(gg_pubdir50_t s)
162 int i;
164 if (!s)
165 return;
167 for (i = 0; i < s->entries_count; i++) {
168 free(s->entries[i].field);
169 free(s->entries[i].value);
172 free(s->entries);
173 free(s);
177 * gg_pubdir50()
179 * wysy³a zapytanie katalogu publicznego do serwera.
181 * - sess - sesja,
182 * - req - zapytanie.
184 * numer sekwencyjny wyszukiwania lub 0 w przypadku b³êdu.
186 uint32_t gg_pubdir50(struct gg_session *sess, gg_pubdir50_t req)
188 int i, size = 5;
189 uint32_t res;
190 char *buf, *p;
191 struct gg_pubdir50_request *r;
193 gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50(%p, %p);\n", sess, req);
195 if (!sess || !req) {
196 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50() invalid arguments\n");
197 errno = EFAULT;
198 return 0;
201 if (sess->state != GG_STATE_CONNECTED) {
202 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50() not connected\n");
203 errno = ENOTCONN;
204 return 0;
207 for (i = 0; i < req->entries_count; i++) {
208 /* wyszukiwanie bierze tylko pierwszy wpis */
209 if (req->entries[i].num)
210 continue;
212 size += strlen(req->entries[i].field) + 1;
213 size += strlen(req->entries[i].value) + 1;
216 if (!(buf = malloc(size))) {
217 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50() out of memory (%d bytes)\n", size);
218 return 0;
221 r = (struct gg_pubdir50_request*) buf;
222 res = time(NULL);
223 r->type = req->type;
224 r->seq = (req->seq) ? gg_fix32(req->seq) : gg_fix32(time(NULL));
225 req->seq = gg_fix32(r->seq);
227 for (i = 0, p = buf + 5; i < req->entries_count; i++) {
228 if (req->entries[i].num)
229 continue;
231 strcpy(p, req->entries[i].field);
232 p += strlen(p) + 1;
234 strcpy(p, req->entries[i].value);
235 p += strlen(p) + 1;
238 if (gg_send_packet(sess, GG_PUBDIR50_REQUEST, buf, size, NULL, 0) == -1)
239 res = 0;
241 free(buf);
243 return res;
247 * gg_pubdir50_handle_reply() // funkcja wewnêtrzna
249 * analizuje przychodz±cy pakiet odpowiedzi i zapisuje wynik w struct gg_event.
251 * - e - opis zdarzenia
252 * - packet - zawarto¶æ pakietu odpowiedzi
253 * - length - d³ugo¶æ pakietu odpowiedzi
255 * 0/-1
257 int gg_pubdir50_handle_reply(struct gg_event *e, const char *packet, int length)
259 const char *end = packet + length, *p;
260 struct gg_pubdir50_reply *r = (struct gg_pubdir50_reply*) packet;
261 gg_pubdir50_t res;
262 int num = 0;
264 gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_handle_reply(%p, %p, %d);\n", e, packet, length);
266 if (!e || !packet) {
267 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_handle_reply() invalid arguments\n");
268 errno = EINVAL;
269 return -1;
272 if (length < 5) {
273 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_handle_reply() packet too short\n");
274 errno = EINVAL;
275 return -1;
278 if (!(res = gg_pubdir50_new(r->type))) {
279 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_handle_reply() unable to allocate reply\n");
280 return -1;
283 e->event.pubdir50 = res;
285 res->seq = gg_fix32(r->seq);
287 switch (res->type) {
288 case GG_PUBDIR50_READ:
289 e->type = GG_EVENT_PUBDIR50_READ;
290 break;
292 case GG_PUBDIR50_WRITE:
293 e->type = GG_EVENT_PUBDIR50_WRITE;
294 break;
296 default:
297 e->type = GG_EVENT_PUBDIR50_SEARCH_REPLY;
298 break;
301 /* brak wyników? */
302 if (length == 5)
303 return 0;
305 /* pomiñ pocz±tek odpowiedzi */
306 p = packet + 5;
308 while (p < end) {
309 const char *field, *value;
311 field = p;
313 /* sprawd¼, czy nie mamy podzia³u na kolejne pole */
314 if (!*field) {
315 num++;
316 field++;
319 value = NULL;
321 for (p = field; p < end; p++) {
322 /* je¶li mamy koniec tekstu... */
323 if (!*p) {
324 /* ...i jeszcze nie mieli¶my warto¶ci pola to
325 * wiemy, ¿e po tym zerze jest warto¶æ... */
326 if (!value)
327 value = p + 1;
328 else
329 /* ...w przeciwym wypadku koniec
330 * warto¶ci i mo¿emy wychodziæ
331 * grzecznie z pêtli */
332 break;
336 /* sprawd¼my, czy pole nie wychodzi poza pakiet, ¿eby nie
337 * mieæ segfaultów, je¶li serwer przestanie zakañczaæ pakietów
338 * przez \0 */
340 if (p == end) {
341 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_handle_reply() premature end of packet\n");
342 goto failure;
345 p++;
347 /* je¶li dostali¶my namier na nastêpne wyniki, to znaczy ¿e
348 * mamy koniec wyników i nie jest to kolejna osoba. */
349 if (!strcasecmp(field, "nextstart")) {
350 res->next = atoi(value);
351 num--;
352 } else {
353 if (gg_pubdir50_add_n(res, num, field, value) == -1)
354 goto failure;
358 res->count = num + 1;
360 return 0;
362 failure:
363 gg_pubdir50_free(res);
364 return -1;
368 * gg_pubdir50_get()
370 * pobiera informacjê z rezultatu wyszukiwania.
372 * - res - rezultat wyszukiwania,
373 * - num - numer odpowiedzi,
374 * - field - nazwa pola (wielko¶æ liter nie ma znaczenia).
376 * warto¶æ pola lub NULL, je¶li nie znaleziono.
378 const char *gg_pubdir50_get(gg_pubdir50_t res, int num, const char *field)
380 char *value = NULL;
381 int i;
383 gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_get(%p, %d, \"%s\");\n", res, num, field);
385 if (!res || num < 0 || !field) {
386 gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_get() invalid arguments\n");
387 errno = EINVAL;
388 return NULL;
391 for (i = 0; i < res->entries_count; i++) {
392 if (res->entries[i].num == num && !strcasecmp(res->entries[i].field, field)) {
393 value = res->entries[i].value;
394 break;
398 return value;
402 * gg_pubdir50_count()
404 * zwraca ilo¶æ wyników danego zapytania.
406 * - res - odpowied¼
408 * ilo¶æ lub -1 w przypadku b³êdu.
410 int gg_pubdir50_count(gg_pubdir50_t res)
412 return (!res) ? -1 : res->count;
416 * gg_pubdir50_type()
418 * zwraca rodzaj zapytania lub odpowiedzi.
420 * - res - zapytanie lub odpowied¼
422 * ilo¶æ lub -1 w przypadku b³êdu.
424 int gg_pubdir50_type(gg_pubdir50_t res)
426 return (!res) ? -1 : res->type;
430 * gg_pubdir50_next()
432 * zwraca numer, od którego nale¿y rozpocz±æ kolejne wyszukiwanie, je¶li
433 * zale¿y nam na kolejnych wynikach.
435 * - res - odpowied¼
437 * numer lub -1 w przypadku b³êdu.
439 uin_t gg_pubdir50_next(gg_pubdir50_t res)
441 return (!res) ? (unsigned) -1 : res->next;
445 * gg_pubdir50_seq()
447 * zwraca numer sekwencyjny zapytania lub odpowiedzi.
449 * - res - zapytanie lub odpowied¼
451 * numer lub -1 w przypadku b³êdu.
453 uint32_t gg_pubdir50_seq(gg_pubdir50_t res)
455 return (!res) ? (unsigned) -1 : res->seq;
459 * Local variables:
460 * c-indentation-style: k&r
461 * c-basic-offset: 8
462 * indent-tabs-mode: notnil
463 * End:
465 * vim: shiftwidth=8: