Mercurial > pidgin
annotate src/protocols/gg/lib/pubdir50.c @ 13253:87a7c3077c19
[gaim-migrate @ 15619]
More cleaning up of oscar. Renamed some functions to be more clear.
Got rid of some stuff that wasn't used. Inlined some small things
in conn.c that were only used once.
The goals of all this are
1. Non-blocking I/O for all connections
2. p2p stuff won't use the same struct as oscar connections, because
that's stupid
3. The oscar PRPL should be less scary
committer: Tailor Script <tailor@pidgin.im>
| author | Mark Doliner <mark@kingant.net> |
|---|---|
| date | Sun, 12 Feb 2006 21:27:04 +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 */ |
