Mercurial > pidgin.yaz
annotate src/protocols/gg/lib/libgadu.c @ 11677:8004885fabbe
[gaim-migrate @ 13963]
Remove some things from the public namespace by making them static
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Mon, 17 Oct 2005 05:50:30 +0000 |
parents | 3c536224f0d0 |
children | 8724718d387f |
rev | line source |
---|---|
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
1 /* $Id: libgadu.c 13801 2005-09-14 19:10:39Z datallah $ */ |
11360 | 2 |
3 /* | |
4 * (C) Copyright 2001-2003 Wojtek Kaniewski <wojtekka@irc.pl> | |
5 * Robert J. Woźny <speedy@ziew.org> | |
6 * Arkadiusz Miśkiewicz <arekm@pld-linux.org> | |
7 * Tomasz Chiliński <chilek@chilan.com> | |
8 * | |
9 * This program is free software; you can redistribute it and/or modify | |
10 * it under the terms of the GNU Lesser General Public License Version | |
11 * 2.1 as published by the Free Software Foundation. | |
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 Lesser General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU Lesser General Public | |
19 * License along with this program; if not, write to the Free Software | |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, | |
21 * USA. | |
22 */ | |
23 | |
24 #include <sys/types.h> | |
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
25 #ifndef _WIN32 |
11360 | 26 #include <sys/wait.h> |
27 #include <sys/socket.h> | |
28 #include <netinet/in.h> | |
29 #include <arpa/inet.h> | |
30 #ifdef sun | |
31 # include <sys/filio.h> | |
32 #endif | |
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
33 #else |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
34 #include <io.h> |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
35 #include <fcntl.h> |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
36 #include <errno.h> |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
37 #define SHUT_RDWR SD_BOTH |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
38 #endif |
11360 | 39 |
40 #include "libgadu-config.h" | |
41 | |
42 #include <errno.h> | |
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
43 #ifndef _WIN32 |
11360 | 44 #include <netdb.h> |
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
45 #endif |
11360 | 46 #ifdef __GG_LIBGADU_HAVE_PTHREAD |
47 # include <pthread.h> | |
48 #endif | |
49 #include <stdarg.h> | |
50 #include <stdio.h> | |
51 #include <stdlib.h> | |
52 #include <string.h> | |
53 #include <unistd.h> | |
54 #ifdef __GG_LIBGADU_HAVE_OPENSSL | |
55 # include <openssl/err.h> | |
56 # include <openssl/rand.h> | |
57 #endif | |
58 | |
59 #include "compat.h" | |
60 #include "libgadu.h" | |
61 | |
62 int gg_debug_level = 0; | |
63 void (*gg_debug_handler)(int level, const char *format, va_list ap) = NULL; | |
64 | |
65 int gg_dcc_port = 0; | |
66 unsigned long gg_dcc_ip = 0; | |
67 | |
68 unsigned long gg_local_ip = 0; | |
69 /* | |
70 * zmienne opisujące parametry proxy http. | |
71 */ | |
72 char *gg_proxy_host = NULL; | |
73 int gg_proxy_port = 0; | |
74 int gg_proxy_enabled = 0; | |
75 int gg_proxy_http_only = 0; | |
76 char *gg_proxy_username = NULL; | |
77 char *gg_proxy_password = NULL; | |
78 | |
79 #ifndef lint | |
80 static char rcsid[] | |
81 #ifdef __GNUC__ | |
82 __attribute__ ((unused)) | |
83 #endif | |
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
84 = "$Id: libgadu.c 13801 2005-09-14 19:10:39Z datallah $"; |
11360 | 85 #endif |
86 | |
87 /* | |
88 * gg_libgadu_version() | |
89 * | |
90 * zwraca wersję libgadu. | |
91 * | |
92 * - brak | |
93 * | |
94 * wersja libgadu. | |
95 */ | |
96 const char *gg_libgadu_version() | |
97 { | |
98 return GG_LIBGADU_VERSION; | |
99 } | |
100 | |
101 /* | |
102 * gg_fix32() | |
103 * | |
104 * zamienia kolejność bajtów w liczbie 32-bitowej tak, by odpowiadała | |
105 * kolejności bajtów w protokole GG. ze względu na LE-owość serwera, | |
106 * zamienia tylko na maszynach BE-wych. | |
107 * | |
108 * - x - liczba do zamiany | |
109 * | |
110 * liczba z odpowiednią kolejnością bajtów. | |
111 */ | |
112 uint32_t gg_fix32(uint32_t x) | |
113 { | |
114 #ifndef __GG_LIBGADU_BIGENDIAN | |
115 return x; | |
116 #else | |
117 return (uint32_t) | |
118 (((x & (uint32_t) 0x000000ffU) << 24) | | |
119 ((x & (uint32_t) 0x0000ff00U) << 8) | | |
120 ((x & (uint32_t) 0x00ff0000U) >> 8) | | |
121 ((x & (uint32_t) 0xff000000U) >> 24)); | |
122 #endif | |
123 } | |
124 | |
125 /* | |
126 * gg_fix16() | |
127 * | |
128 * zamienia kolejność bajtów w liczbie 16-bitowej tak, by odpowiadała | |
129 * kolejności bajtów w protokole GG. ze względu na LE-owość serwera, | |
130 * zamienia tylko na maszynach BE-wych. | |
131 * | |
132 * - x - liczba do zamiany | |
133 * | |
134 * liczba z odpowiednią kolejnością bajtów. | |
135 */ | |
136 uint16_t gg_fix16(uint16_t x) | |
137 { | |
138 #ifndef __GG_LIBGADU_BIGENDIAN | |
139 return x; | |
140 #else | |
141 return (uint16_t) | |
142 (((x & (uint16_t) 0x00ffU) << 8) | | |
143 ((x & (uint16_t) 0xff00U) >> 8)); | |
144 #endif | |
145 } | |
146 | |
147 /* | |
148 * gg_login_hash() // funkcja wewnętrzna | |
149 * | |
150 * liczy hash z hasła i danego seeda. | |
151 * | |
152 * - password - hasło do hashowania | |
153 * - seed - wartość podana przez serwer | |
154 * | |
155 * hash. | |
156 */ | |
157 unsigned int gg_login_hash(const unsigned char *password, unsigned int seed) | |
158 { | |
159 unsigned int x, y, z; | |
160 | |
161 y = seed; | |
162 | |
163 for (x = 0; *password; password++) { | |
164 x = (x & 0xffffff00) | *password; | |
165 y ^= x; | |
166 y += x; | |
167 x <<= 8; | |
168 y ^= x; | |
169 x <<= 8; | |
170 y -= x; | |
171 x <<= 8; | |
172 y ^= x; | |
173 | |
174 z = y & 0x1F; | |
175 y = (y << z) | (y >> (32 - z)); | |
176 } | |
177 | |
178 return y; | |
179 } | |
180 | |
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
181 #ifndef _WIN32 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
182 |
11360 | 183 /* |
184 * gg_resolve() // funkcja wewnętrzna | |
185 * | |
186 * tworzy potok, forkuje się i w drugim procesie zaczyna resolvować | |
187 * podanego hosta. zapisuje w sesji deskryptor potoku. jeśli coś tam | |
188 * będzie gotowego, znaczy, że można wczytać struct in_addr. jeśli | |
189 * nie znajdzie, zwraca INADDR_NONE. | |
190 * | |
191 * - fd - wskaźnik gdzie wrzucić deskryptor | |
192 * - pid - gdzie wrzucić pid procesu potomnego | |
193 * - hostname - nazwa hosta do zresolvowania | |
194 * | |
195 * 0, -1. | |
196 */ | |
197 int gg_resolve(int *fd, int *pid, const char *hostname) | |
198 { | |
199 int pipes[2], res; | |
200 struct in_addr a; | |
201 int errno2; | |
202 | |
203 gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve(%p, %p, \"%s\");\n", fd, pid, hostname); | |
204 | |
205 if (!fd || !pid) { | |
206 errno = EFAULT; | |
207 return -1; | |
208 } | |
209 | |
210 if (pipe(pipes) == -1) | |
211 return -1; | |
212 | |
213 if ((res = fork()) == -1) { | |
214 errno2 = errno; | |
215 close(pipes[0]); | |
216 close(pipes[1]); | |
217 errno = errno2; | |
218 return -1; | |
219 } | |
220 | |
221 if (!res) { | |
222 if ((a.s_addr = inet_addr(hostname)) == INADDR_NONE) { | |
223 struct in_addr *hn; | |
224 | |
225 if (!(hn = gg_gethostbyname(hostname))) | |
226 a.s_addr = INADDR_NONE; | |
227 else { | |
228 a.s_addr = hn->s_addr; | |
229 free(hn); | |
230 } | |
231 } | |
232 | |
233 write(pipes[1], &a, sizeof(a)); | |
234 | |
235 exit(0); | |
236 } | |
237 | |
238 close(pipes[1]); | |
239 | |
240 *fd = pipes[0]; | |
241 *pid = res; | |
242 | |
243 return 0; | |
244 } | |
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
245 #endif |
11360 | 246 |
247 #ifdef __GG_LIBGADU_HAVE_PTHREAD | |
248 | |
249 struct gg_resolve_pthread_data { | |
250 char *hostname; | |
251 int fd; | |
252 }; | |
253 | |
254 static void *gg_resolve_pthread_thread(void *arg) | |
255 { | |
256 struct gg_resolve_pthread_data *d = arg; | |
257 struct in_addr a; | |
258 | |
259 pthread_detach(pthread_self()); | |
260 | |
261 if ((a.s_addr = inet_addr(d->hostname)) == INADDR_NONE) { | |
262 struct in_addr *hn; | |
263 | |
264 if (!(hn = gg_gethostbyname(d->hostname))) | |
265 a.s_addr = INADDR_NONE; | |
266 else { | |
267 a.s_addr = hn->s_addr; | |
268 free(hn); | |
269 } | |
270 } | |
271 | |
272 write(d->fd, &a, sizeof(a)); | |
273 close(d->fd); | |
274 | |
275 free(d->hostname); | |
276 d->hostname = NULL; | |
277 | |
278 free(d); | |
279 | |
280 pthread_exit(NULL); | |
281 | |
282 return NULL; /* żeby kompilator nie marudził */ | |
283 } | |
284 | |
285 /* | |
286 * gg_resolve_pthread() // funkcja wewnętrzna | |
287 * | |
288 * tworzy potok, nowy wątek i w nim zaczyna resolvować podanego hosta. | |
289 * zapisuje w sesji deskryptor potoku. jeśli coś tam będzie gotowego, | |
290 * znaczy, że można wczytać struct in_addr. jeśli nie znajdzie, zwraca | |
291 * INADDR_NONE. | |
292 * | |
293 * - fd - wskaźnik do zmiennej przechowującej desktyptor resolvera | |
294 * - resolver - wskaźnik do wskaźnika resolvera | |
295 * - hostname - nazwa hosta do zresolvowania | |
296 * | |
297 * 0, -1. | |
298 */ | |
299 int gg_resolve_pthread(int *fd, void **resolver, const char *hostname) | |
300 { | |
301 struct gg_resolve_pthread_data *d = NULL; | |
302 pthread_t *tmp; | |
303 int pipes[2], new_errno; | |
304 | |
305 gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve_pthread(%p, %p, \"%s\");\n", fd, resolver, hostname); | |
306 | |
307 if (!resolver || !fd || !hostname) { | |
308 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() invalid arguments\n"); | |
309 errno = EFAULT; | |
310 return -1; | |
311 } | |
312 | |
313 if (!(tmp = malloc(sizeof(pthread_t)))) { | |
314 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory for pthread id\n"); | |
315 return -1; | |
316 } | |
317 | |
318 if (pipe(pipes) == -1) { | |
319 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() unable to create pipes (errno=%d, %s)\n", errno, strerror(errno)); | |
320 free(tmp); | |
321 return -1; | |
322 } | |
323 | |
324 if (!(d = malloc(sizeof(*d)))) { | |
325 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory\n"); | |
326 new_errno = errno; | |
327 goto cleanup; | |
328 } | |
329 | |
330 d->hostname = NULL; | |
331 | |
332 if (!(d->hostname = strdup(hostname))) { | |
333 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory\n"); | |
334 new_errno = errno; | |
335 goto cleanup; | |
336 } | |
337 | |
338 d->fd = pipes[1]; | |
339 | |
340 if (pthread_create(tmp, NULL, gg_resolve_pthread_thread, d)) { | |
341 gg_debug(GG_DEBUG_MISC, "// gg_resolve_phread() unable to create thread\n"); | |
342 new_errno = errno; | |
343 goto cleanup; | |
344 } | |
345 | |
346 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() %p\n", tmp); | |
347 | |
348 *resolver = tmp; | |
349 | |
350 *fd = pipes[0]; | |
351 | |
352 return 0; | |
353 | |
354 cleanup: | |
355 if (d) { | |
356 free(d->hostname); | |
357 free(d); | |
358 } | |
359 | |
360 close(pipes[0]); | |
361 close(pipes[1]); | |
362 | |
363 free(tmp); | |
364 | |
365 errno = new_errno; | |
366 | |
367 return -1; | |
368 } | |
369 | |
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
370 #elif defined _WIN32 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
371 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
372 struct gg_resolve_win32thread_data { |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
373 char *hostname; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
374 int fd; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
375 }; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
376 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
377 static DWORD WINAPI gg_resolve_win32thread_thread(LPVOID arg) |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
378 { |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
379 struct gg_resolve_win32thread_data *d = arg; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
380 struct in_addr a; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
381 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
382 if ((a.s_addr = inet_addr(d->hostname)) == INADDR_NONE) { |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
383 struct in_addr *hn; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
384 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
385 if (!(hn = gg_gethostbyname(d->hostname))) |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
386 a.s_addr = INADDR_NONE; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
387 else { |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
388 a.s_addr = hn->s_addr; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
389 free(hn); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
390 } |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
391 } |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
392 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
393 write(d->fd, &a, sizeof(a)); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
394 close(d->fd); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
395 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
396 free(d->hostname); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
397 d->hostname = NULL; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
398 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
399 free(d); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
400 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
401 return 0; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
402 } |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
403 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
404 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
405 int gg_resolve_win32thread(int *fd, void **resolver, const char *hostname) |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
406 { |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
407 struct gg_resolve_win32thread_data *d = NULL; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
408 HANDLE h; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
409 DWORD dwTId; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
410 int pipes[2], new_errno; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
411 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
412 gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve_win32thread(%p, %p, \"%s\");\n", fd, resolver, hostname); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
413 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
414 if (!resolver || !fd || !hostname) { |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
415 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() invalid arguments\n"); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
416 errno = EFAULT; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
417 return -1; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
418 } |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
419 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
420 if (pipe(pipes) == -1) { |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
421 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() unable to create pipes (errno=%d, %s)\n", errno, strerror(errno)); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
422 return -1; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
423 } |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
424 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
425 if (!(d = malloc(sizeof(*d)))) { |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
426 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() out of memory\n"); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
427 new_errno = GetLastError(); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
428 goto cleanup; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
429 } |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
430 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
431 d->hostname = NULL; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
432 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
433 if (!(d->hostname = strdup(hostname))) { |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
434 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() out of memory\n"); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
435 new_errno = GetLastError(); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
436 goto cleanup; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
437 } |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
438 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
439 d->fd = pipes[1]; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
440 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
441 h = CreateThread(NULL, 0, gg_resolve_win32thread_thread, |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
442 d, 0, &dwTId); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
443 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
444 if (h == NULL) { |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
445 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() unable to create thread\n"); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
446 new_errno = GetLastError(); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
447 goto cleanup; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
448 } |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
449 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
450 *resolver = h; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
451 *fd = pipes[0]; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
452 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
453 return 0; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
454 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
455 cleanup: |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
456 if (d) { |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
457 free(d->hostname); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
458 free(d); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
459 } |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
460 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
461 close(pipes[0]); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
462 close(pipes[1]); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
463 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
464 errno = new_errno; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
465 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
466 return -1; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
467 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
468 } |
11360 | 469 #endif |
470 | |
471 /* | |
472 * gg_read() // funkcja pomocnicza | |
473 * | |
474 * czyta z gniazda określoną ilość bajtów. bierze pod uwagę, czy mamy | |
475 * połączenie zwykłe czy TLS. | |
476 * | |
477 * - sess - sesja, | |
478 * - buf - bufor, | |
479 * - length - ilość bajtów, | |
480 * | |
481 * takie same wartości jak read(). | |
482 */ | |
483 int gg_read(struct gg_session *sess, char *buf, int length) | |
484 { | |
485 int res; | |
486 | |
487 #ifdef __GG_LIBGADU_HAVE_OPENSSL | |
488 if (sess->ssl) { | |
489 int err; | |
490 | |
491 res = SSL_read(sess->ssl, buf, length); | |
492 | |
493 if (res < 0) { | |
494 err = SSL_get_error(sess->ssl, res); | |
495 | |
496 if (err == SSL_ERROR_WANT_READ) | |
497 errno = EAGAIN; | |
498 | |
499 return -1; | |
500 } | |
501 } else | |
502 #endif | |
503 res = read(sess->fd, buf, length); | |
504 | |
505 return res; | |
506 } | |
507 | |
508 /* | |
509 * gg_write() // funkcja pomocnicza | |
510 * | |
511 * zapisuje do gniazda określoną ilość bajtów. bierze pod uwagę, czy mamy | |
512 * połączenie zwykłe czy TLS. | |
513 * | |
514 * - sess - sesja, | |
515 * - buf - bufor, | |
516 * - length - ilość bajtów, | |
517 * | |
518 * takie same wartości jak write(). | |
519 */ | |
520 int gg_write(struct gg_session *sess, const char *buf, int length) | |
521 { | |
522 int res = 0; | |
523 | |
524 #ifdef __GG_LIBGADU_HAVE_OPENSSL | |
525 if (sess->ssl) { | |
526 int err; | |
527 | |
528 res = SSL_write(sess->ssl, buf, length); | |
529 | |
530 if (res < 0) { | |
531 err = SSL_get_error(sess->ssl, res); | |
532 | |
533 if (err == SSL_ERROR_WANT_WRITE) | |
534 errno = EAGAIN; | |
535 | |
536 return -1; | |
537 } | |
538 } else | |
539 #endif | |
540 { | |
541 int written = 0; | |
542 | |
543 while (written < length) { | |
544 res = write(sess->fd, buf + written, length - written); | |
545 | |
546 if (res == -1) { | |
547 if (errno == EAGAIN) | |
548 continue; | |
549 else | |
550 break; | |
551 } else { | |
552 written += res; | |
553 res = written; | |
554 } | |
555 } | |
556 } | |
557 | |
558 return res; | |
559 } | |
560 | |
561 /* | |
562 * gg_recv_packet() // funkcja wewnętrzna | |
563 * | |
564 * odbiera jeden pakiet i zwraca wskaźnik do niego. pamięć po nim | |
565 * należy zwolnić za pomocą free(). | |
566 * | |
567 * - sess - opis sesji | |
568 * | |
569 * w przypadku błędu NULL, kod błędu w errno. należy zwrócić uwagę, że gdy | |
570 * połączenie jest nieblokujące, a kod błędu wynosi EAGAIN, nie udało się | |
571 * odczytać całego pakietu i nie należy tego traktować jako błąd. | |
572 */ | |
573 void *gg_recv_packet(struct gg_session *sess) | |
574 { | |
575 struct gg_header h; | |
576 char *buf = NULL; | |
577 int ret = 0; | |
578 unsigned int offset, size = 0; | |
579 | |
580 gg_debug(GG_DEBUG_FUNCTION, "** gg_recv_packet(%p);\n", sess); | |
581 | |
582 if (!sess) { | |
583 errno = EFAULT; | |
584 return NULL; | |
585 } | |
586 | |
587 if (sess->recv_left < 1) { | |
588 if (sess->header_buf) { | |
589 memcpy(&h, sess->header_buf, sess->header_done); | |
590 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv: resuming last read (%d bytes left)\n", sizeof(h) - sess->header_done); | |
591 free(sess->header_buf); | |
592 sess->header_buf = NULL; | |
593 } else | |
594 sess->header_done = 0; | |
595 | |
596 while (sess->header_done < sizeof(h)) { | |
597 ret = gg_read(sess, (char*) &h + sess->header_done, sizeof(h) - sess->header_done); | |
598 | |
599 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv(%d,%p,%d) = %d\n", sess->fd, &h + sess->header_done, sizeof(h) - sess->header_done, ret); | |
600 | |
601 if (!ret) { | |
602 errno = ECONNRESET; | |
603 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: connection broken\n"); | |
604 return NULL; | |
605 } | |
606 | |
607 if (ret == -1) { | |
608 if (errno == EINTR) { | |
609 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() interrupted system call, resuming\n"); | |
610 continue; | |
611 } | |
612 | |
613 if (errno == EAGAIN) { | |
614 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() incomplete header received\n"); | |
615 | |
616 if (!(sess->header_buf = malloc(sess->header_done))) { | |
617 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() not enough memory\n"); | |
618 return NULL; | |
619 } | |
620 | |
621 memcpy(sess->header_buf, &h, sess->header_done); | |
622 | |
623 return NULL; | |
624 } | |
625 | |
626 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: errno=%d, %s\n", errno, strerror(errno)); | |
627 | |
628 return NULL; | |
629 } | |
630 | |
631 sess->header_done += ret; | |
632 | |
633 } | |
634 | |
635 h.type = gg_fix32(h.type); | |
636 h.length = gg_fix32(h.length); | |
637 } else | |
638 memcpy(&h, sess->recv_buf, sizeof(h)); | |
639 | |
640 /* jakieś sensowne limity na rozmiar pakietu */ | |
641 if (h.length > 65535) { | |
642 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() invalid packet length (%d)\n", h.length); | |
643 errno = ERANGE; | |
644 return NULL; | |
645 } | |
646 | |
647 if (sess->recv_left > 0) { | |
648 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() resuming last gg_recv_packet()\n"); | |
649 size = sess->recv_left; | |
650 offset = sess->recv_done; | |
651 buf = sess->recv_buf; | |
652 } else { | |
653 if (!(buf = malloc(sizeof(h) + h.length + 1))) { | |
654 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() not enough memory for packet data\n"); | |
655 return NULL; | |
656 } | |
657 | |
658 memcpy(buf, &h, sizeof(h)); | |
659 | |
660 offset = 0; | |
661 size = h.length; | |
662 } | |
663 | |
664 while (size > 0) { | |
665 ret = gg_read(sess, buf + sizeof(h) + offset, size); | |
666 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv(%d,%p,%d) = %d\n", sess->fd, buf + sizeof(h) + offset, size, ret); | |
667 if (!ret) { | |
668 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed: connection broken\n"); | |
669 errno = ECONNRESET; | |
670 return NULL; | |
671 } | |
672 if (ret > -1 && ret <= size) { | |
673 offset += ret; | |
674 size -= ret; | |
675 } else if (ret == -1) { | |
676 int errno2 = errno; | |
677 | |
678 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed (errno=%d, %s)\n", errno, strerror(errno)); | |
679 errno = errno2; | |
680 | |
681 if (errno == EAGAIN) { | |
682 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() %d bytes received, %d left\n", offset, size); | |
683 sess->recv_buf = buf; | |
684 sess->recv_left = size; | |
685 sess->recv_done = offset; | |
686 return NULL; | |
687 } | |
688 if (errno != EINTR) { | |
689 free(buf); | |
690 return NULL; | |
691 } | |
692 } | |
693 } | |
694 | |
695 sess->recv_left = 0; | |
696 | |
697 if ((gg_debug_level & GG_DEBUG_DUMP)) { | |
698 unsigned int i; | |
699 | |
700 gg_debug(GG_DEBUG_DUMP, "// gg_recv_packet(%.2x)", h.type); | |
701 for (i = 0; i < sizeof(h) + h.length; i++) | |
702 gg_debug(GG_DEBUG_DUMP, " %.2x", (unsigned char) buf[i]); | |
703 gg_debug(GG_DEBUG_DUMP, "\n"); | |
704 } | |
705 | |
706 return buf; | |
707 } | |
708 | |
709 /* | |
710 * gg_send_packet() // funkcja wewnętrzna | |
711 * | |
712 * konstruuje pakiet i wysyła go do serwera. | |
713 * | |
714 * - sock - deskryptor gniazda | |
715 * - type - typ pakietu | |
716 * - payload_1 - pierwsza część pakietu | |
717 * - payload_length_1 - długość pierwszej części | |
718 * - payload_2 - druga część pakietu | |
719 * - payload_length_2 - długość drugiej części | |
720 * - ... - kolejne części pakietu i ich długości | |
721 * - NULL - końcowym parametr (konieczny!) | |
722 * | |
723 * jeśli się powiodło, zwraca 0, w przypadku błędu -1. jeśli errno == ENOMEM, | |
724 * zabrakło pamięci. inaczej był błąd przy wysyłaniu pakietu. dla errno == 0 | |
725 * nie wysłano całego pakietu. | |
726 */ | |
727 int gg_send_packet(struct gg_session *sess, int type, ...) | |
728 { | |
729 struct gg_header *h; | |
730 char *tmp; | |
731 unsigned int tmp_length; | |
732 void *payload; | |
733 unsigned int payload_length; | |
734 va_list ap; | |
735 int res; | |
736 | |
737 gg_debug(GG_DEBUG_FUNCTION, "** gg_send_packet(%p, 0x%.2x, ...)\n", sess, type); | |
738 | |
739 tmp_length = sizeof(struct gg_header); | |
740 | |
741 if (!(tmp = malloc(tmp_length))) { | |
742 gg_debug(GG_DEBUG_MISC, "// gg_send_packet() not enough memory for packet header\n"); | |
743 return -1; | |
744 } | |
745 | |
746 va_start(ap, type); | |
747 | |
748 payload = va_arg(ap, void *); | |
749 | |
750 while (payload) { | |
751 char *tmp2; | |
752 | |
753 payload_length = va_arg(ap, unsigned int); | |
754 | |
755 if (!(tmp2 = realloc(tmp, tmp_length + payload_length))) { | |
756 gg_debug(GG_DEBUG_MISC, "// gg_send_packet() not enough memory for payload\n"); | |
757 free(tmp); | |
758 va_end(ap); | |
759 return -1; | |
760 } | |
761 | |
762 tmp = tmp2; | |
763 | |
764 memcpy(tmp + tmp_length, payload, payload_length); | |
765 tmp_length += payload_length; | |
766 | |
767 payload = va_arg(ap, void *); | |
768 } | |
769 | |
770 va_end(ap); | |
771 | |
772 h = (struct gg_header*) tmp; | |
773 h->type = gg_fix32(type); | |
774 h->length = gg_fix32(tmp_length - sizeof(struct gg_header)); | |
775 | |
776 if ((gg_debug_level & GG_DEBUG_DUMP)) { | |
777 unsigned int i; | |
778 | |
779 gg_debug(GG_DEBUG_DUMP, "// gg_send_packet(0x%.2x)", gg_fix32(h->type)); | |
780 for (i = 0; i < tmp_length; ++i) | |
781 gg_debug(GG_DEBUG_DUMP, " %.2x", (unsigned char) tmp[i]); | |
782 gg_debug(GG_DEBUG_DUMP, "\n"); | |
783 } | |
784 | |
785 if ((res = gg_write(sess, tmp, tmp_length)) < tmp_length) { | |
786 gg_debug(GG_DEBUG_MISC, "// gg_send_packet() write() failed. res = %d, errno = %d (%s)\n", res, errno, strerror(errno)); | |
787 free(tmp); | |
788 return -1; | |
789 } | |
790 | |
791 free(tmp); | |
792 return 0; | |
793 } | |
794 | |
795 /* | |
796 * gg_session_callback() // funkcja wewnętrzna | |
797 * | |
798 * wywoływany z gg_session->callback, wykonuje gg_watch_fd() i pakuje | |
799 * do gg_session->event jego wynik. | |
800 */ | |
801 static int gg_session_callback(struct gg_session *s) | |
802 { | |
803 if (!s) { | |
804 errno = EFAULT; | |
805 return -1; | |
806 } | |
807 | |
808 return ((s->event = gg_watch_fd(s)) != NULL) ? 0 : -1; | |
809 } | |
810 | |
811 /* | |
812 * gg_login() | |
813 * | |
814 * rozpoczyna procedurę łączenia się z serwerem. resztę obsługuje się przez | |
815 * gg_watch_fd(). | |
816 * | |
817 * UWAGA! program musi obsłużyć SIGCHLD, jeśli łączy się asynchronicznie, | |
818 * żeby poprawnie zamknąć proces resolvera. | |
819 * | |
820 * - p - struktura opisująca początkowy stan. wymagane pola: uin, | |
821 * password | |
822 * | |
823 * w przypadku błędu NULL, jeśli idzie dobrze (async) albo poszło | |
824 * dobrze (sync), zwróci wskaźnik do zaalokowanej struct gg_session. | |
825 */ | |
826 struct gg_session *gg_login(const struct gg_login_params *p) | |
827 { | |
828 struct gg_session *sess = NULL; | |
829 char *hostname; | |
830 int port; | |
831 | |
832 if (!p) { | |
833 gg_debug(GG_DEBUG_FUNCTION, "** gg_login(%p);\n", p); | |
834 errno = EFAULT; | |
835 return NULL; | |
836 } | |
837 | |
838 gg_debug(GG_DEBUG_FUNCTION, "** gg_login(%p: [uin=%u, async=%d, ...]);\n", p, p->uin, p->async); | |
839 | |
840 if (!(sess = malloc(sizeof(struct gg_session)))) { | |
841 gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for session data\n"); | |
842 goto fail; | |
843 } | |
844 | |
845 memset(sess, 0, sizeof(struct gg_session)); | |
846 | |
847 if (!p->password || !p->uin) { | |
848 gg_debug(GG_DEBUG_MISC, "// gg_login() invalid arguments. uin and password needed\n"); | |
849 errno = EFAULT; | |
850 goto fail; | |
851 } | |
852 | |
853 if (!(sess->password = strdup(p->password))) { | |
854 gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for password\n"); | |
855 goto fail; | |
856 } | |
857 | |
858 if (p->status_descr && !(sess->initial_descr = strdup(p->status_descr))) { | |
859 gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for status\n"); | |
860 goto fail; | |
861 } | |
862 | |
863 sess->uin = p->uin; | |
864 sess->state = GG_STATE_RESOLVING; | |
865 sess->check = GG_CHECK_READ; | |
866 sess->timeout = GG_DEFAULT_TIMEOUT; | |
867 sess->async = p->async; | |
868 sess->type = GG_SESSION_GG; | |
869 sess->initial_status = p->status; | |
870 sess->callback = gg_session_callback; | |
871 sess->destroy = gg_free_session; | |
872 sess->port = (p->server_port) ? p->server_port : ((gg_proxy_enabled) ? GG_HTTPS_PORT : GG_DEFAULT_PORT); | |
873 sess->server_addr = p->server_addr; | |
874 sess->external_port = p->external_port; | |
875 sess->external_addr = p->external_addr; | |
876 sess->protocol_version = (p->protocol_version) ? p->protocol_version : GG_DEFAULT_PROTOCOL_VERSION; | |
877 if (p->era_omnix) | |
878 sess->protocol_version |= GG_ERA_OMNIX_MASK; | |
879 if (p->has_audio) | |
880 sess->protocol_version |= GG_HAS_AUDIO_MASK; | |
881 sess->client_version = (p->client_version) ? strdup(p->client_version) : NULL; | |
882 sess->last_sysmsg = p->last_sysmsg; | |
883 sess->image_size = p->image_size; | |
884 sess->pid = -1; | |
885 | |
886 if (p->tls == 1) { | |
887 #ifdef __GG_LIBGADU_HAVE_OPENSSL | |
888 char buf[1024]; | |
889 | |
890 OpenSSL_add_ssl_algorithms(); | |
891 | |
892 if (!RAND_status()) { | |
893 char rdata[1024]; | |
894 struct { | |
895 time_t time; | |
896 void *ptr; | |
897 } rstruct; | |
898 | |
899 time(&rstruct.time); | |
900 rstruct.ptr = (void *) &rstruct; | |
901 | |
902 RAND_seed((void *) rdata, sizeof(rdata)); | |
903 RAND_seed((void *) &rstruct, sizeof(rstruct)); | |
904 } | |
905 | |
906 sess->ssl_ctx = SSL_CTX_new(TLSv1_client_method()); | |
907 | |
908 if (!sess->ssl_ctx) { | |
909 ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); | |
910 gg_debug(GG_DEBUG_MISC, "// gg_login() SSL_CTX_new() failed: %s\n", buf); | |
911 goto fail; | |
912 } | |
913 | |
914 SSL_CTX_set_verify(sess->ssl_ctx, SSL_VERIFY_NONE, NULL); | |
915 | |
916 sess->ssl = SSL_new(sess->ssl_ctx); | |
917 | |
918 if (!sess->ssl) { | |
919 ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); | |
920 gg_debug(GG_DEBUG_MISC, "// gg_login() SSL_new() failed: %s\n", buf); | |
921 goto fail; | |
922 } | |
923 #else | |
924 gg_debug(GG_DEBUG_MISC, "// gg_login() client requested TLS but no support compiled in\n"); | |
925 #endif | |
926 } | |
927 | |
928 if (gg_proxy_enabled) { | |
929 hostname = gg_proxy_host; | |
930 sess->proxy_port = port = gg_proxy_port; | |
931 } else { | |
932 hostname = GG_APPMSG_HOST; | |
933 port = GG_APPMSG_PORT; | |
934 } | |
935 | |
936 if (!p->async) { | |
937 struct in_addr a; | |
938 | |
939 if (!p->server_addr || !p->server_port) { | |
940 if ((a.s_addr = inet_addr(hostname)) == INADDR_NONE) { | |
941 struct in_addr *hn; | |
942 | |
943 if (!(hn = gg_gethostbyname(hostname))) { | |
944 gg_debug(GG_DEBUG_MISC, "// gg_login() host \"%s\" not found\n", hostname); | |
945 goto fail; | |
946 } else { | |
947 a.s_addr = hn->s_addr; | |
948 free(hn); | |
949 } | |
950 } | |
951 } else { | |
952 a.s_addr = p->server_addr; | |
953 port = p->server_port; | |
954 } | |
955 | |
956 sess->hub_addr = a.s_addr; | |
957 | |
958 if (gg_proxy_enabled) | |
959 sess->proxy_addr = a.s_addr; | |
960 | |
961 if ((sess->fd = gg_connect(&a, port, 0)) == -1) { | |
962 gg_debug(GG_DEBUG_MISC, "// gg_login() connection failed (errno=%d, %s)\n", errno, strerror(errno)); | |
963 goto fail; | |
964 } | |
965 | |
966 if (p->server_addr && p->server_port) | |
967 sess->state = GG_STATE_CONNECTING_GG; | |
968 else | |
969 sess->state = GG_STATE_CONNECTING_HUB; | |
970 | |
971 while (sess->state != GG_STATE_CONNECTED) { | |
972 struct gg_event *e; | |
973 | |
974 if (!(e = gg_watch_fd(sess))) { | |
975 gg_debug(GG_DEBUG_MISC, "// gg_login() critical error in gg_watch_fd()\n"); | |
976 goto fail; | |
977 } | |
978 | |
979 if (e->type == GG_EVENT_CONN_FAILED) { | |
980 errno = EACCES; | |
981 gg_debug(GG_DEBUG_MISC, "// gg_login() could not login\n"); | |
982 gg_event_free(e); | |
983 goto fail; | |
984 } | |
985 | |
986 gg_event_free(e); | |
987 } | |
988 | |
989 return sess; | |
990 } | |
991 | |
992 if (!sess->server_addr || gg_proxy_enabled) { | |
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
993 #ifdef __GG_LIBGADU_HAVE_PTHREAD |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
994 if (gg_resolve_pthread(&sess->fd, &sess->resolver, hostname)) { |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
995 #elif defined _WIN32 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
996 if (gg_resolve_win32thread(&sess->fd, &sess->resolver, hostname)) { |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
997 #else |
11360 | 998 if (gg_resolve(&sess->fd, &sess->pid, hostname)) { |
999 #endif | |
1000 gg_debug(GG_DEBUG_MISC, "// gg_login() resolving failed (errno=%d, %s)\n", errno, strerror(errno)); | |
1001 goto fail; | |
1002 } | |
1003 } else { | |
1004 if ((sess->fd = gg_connect(&sess->server_addr, sess->port, sess->async)) == -1) { | |
1005 gg_debug(GG_DEBUG_MISC, "// gg_login() direct connection failed (errno=%d, %s)\n", errno, strerror(errno)); | |
1006 goto fail; | |
1007 } | |
1008 sess->state = GG_STATE_CONNECTING_GG; | |
1009 sess->check = GG_CHECK_WRITE; | |
1010 } | |
1011 | |
1012 return sess; | |
1013 | |
1014 fail: | |
1015 if (sess) { | |
1016 if (sess->password) | |
1017 free(sess->password); | |
1018 if (sess->initial_descr) | |
1019 free(sess->initial_descr); | |
1020 free(sess); | |
1021 } | |
1022 | |
1023 return NULL; | |
1024 } | |
1025 | |
1026 /* | |
1027 * gg_free_session() | |
1028 * | |
1029 * próbuje zamknąć połączenia i zwalnia pamięć zajmowaną przez sesję. | |
1030 * | |
1031 * - sess - opis sesji | |
1032 */ | |
1033 void gg_free_session(struct gg_session *sess) | |
1034 { | |
1035 if (!sess) | |
1036 return; | |
1037 | |
1038 /* XXX dopisać zwalnianie i zamykanie wszystkiego, co mogło zostać */ | |
1039 | |
1040 if (sess->password) | |
1041 free(sess->password); | |
1042 | |
1043 if (sess->initial_descr) | |
1044 free(sess->initial_descr); | |
1045 | |
1046 if (sess->client_version) | |
1047 free(sess->client_version); | |
1048 | |
1049 if (sess->header_buf) | |
1050 free(sess->header_buf); | |
1051 | |
1052 #ifdef __GG_LIBGADU_HAVE_OPENSSL | |
1053 if (sess->ssl) | |
1054 SSL_free(sess->ssl); | |
1055 | |
1056 if (sess->ssl_ctx) | |
1057 SSL_CTX_free(sess->ssl_ctx); | |
1058 #endif | |
1059 | |
1060 #ifdef __GG_LIBGADU_HAVE_PTHREAD | |
1061 if (sess->resolver) { | |
1062 pthread_cancel(*((pthread_t*) sess->resolver)); | |
1063 free(sess->resolver); | |
1064 sess->resolver = NULL; | |
1065 } | |
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
1066 #elif defined _WIN32 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
1067 if (sess->resolver) { |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
1068 HANDLE h = sess->resolver; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
1069 TerminateThread(h, 0); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
1070 CloseHandle(h); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
1071 sess->resolver = NULL; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
1072 } |
11360 | 1073 #else |
1074 if (sess->pid != -1) | |
1075 waitpid(sess->pid, NULL, WNOHANG); | |
1076 #endif | |
1077 | |
1078 if (sess->fd != -1) | |
1079 close(sess->fd); | |
1080 | |
1081 while (sess->images) | |
1082 gg_image_queue_remove(sess, sess->images, 1); | |
1083 | |
1084 free(sess); | |
1085 } | |
1086 | |
1087 /* | |
1088 * gg_change_status() | |
1089 * | |
1090 * zmienia status użytkownika. przydatne do /away i /busy oraz /quit. | |
1091 * | |
1092 * - sess - opis sesji | |
1093 * - status - nowy status użytkownika | |
1094 * | |
1095 * 0, -1. | |
1096 */ | |
1097 int gg_change_status(struct gg_session *sess, int status) | |
1098 { | |
1099 struct gg_new_status p; | |
1100 | |
1101 gg_debug(GG_DEBUG_FUNCTION, "** gg_change_status(%p, %d);\n", sess, status); | |
1102 | |
1103 if (!sess) { | |
1104 errno = EFAULT; | |
1105 return -1; | |
1106 } | |
1107 | |
1108 if (sess->state != GG_STATE_CONNECTED) { | |
1109 errno = ENOTCONN; | |
1110 return -1; | |
1111 } | |
1112 | |
1113 p.status = gg_fix32(status); | |
1114 | |
1115 sess->status = status; | |
1116 | |
1117 return gg_send_packet(sess, GG_NEW_STATUS, &p, sizeof(p), NULL); | |
1118 } | |
1119 | |
1120 /* | |
1121 * gg_change_status_descr() | |
1122 * | |
1123 * zmienia status użytkownika na opisowy. | |
1124 * | |
1125 * - sess - opis sesji | |
1126 * - status - nowy status użytkownika | |
1127 * - descr - opis statusu | |
1128 * | |
1129 * 0, -1. | |
1130 */ | |
1131 int gg_change_status_descr(struct gg_session *sess, int status, const char *descr) | |
1132 { | |
1133 struct gg_new_status p; | |
1134 | |
1135 gg_debug(GG_DEBUG_FUNCTION, "** gg_change_status_descr(%p, %d, \"%s\");\n", sess, status, descr); | |
1136 | |
1137 if (!sess || !descr) { | |
1138 errno = EFAULT; | |
1139 return -1; | |
1140 } | |
1141 | |
1142 if (sess->state != GG_STATE_CONNECTED) { | |
1143 errno = ENOTCONN; | |
1144 return -1; | |
1145 } | |
1146 | |
1147 p.status = gg_fix32(status); | |
1148 | |
1149 sess->status = status; | |
1150 | |
1151 return gg_send_packet(sess, GG_NEW_STATUS, &p, sizeof(p), descr, (strlen(descr) > GG_STATUS_DESCR_MAXSIZE) ? GG_STATUS_DESCR_MAXSIZE : strlen(descr), NULL); | |
1152 } | |
1153 | |
1154 /* | |
1155 * gg_change_status_descr_time() | |
1156 * | |
1157 * zmienia status użytkownika na opisowy z godziną powrotu. | |
1158 * | |
1159 * - sess - opis sesji | |
1160 * - status - nowy status użytkownika | |
1161 * - descr - opis statusu | |
1162 * - time - czas w formacie uniksowym | |
1163 * | |
1164 * 0, -1. | |
1165 */ | |
1166 int gg_change_status_descr_time(struct gg_session *sess, int status, const char *descr, int time) | |
1167 { | |
1168 struct gg_new_status p; | |
1169 uint32_t newtime; | |
1170 | |
1171 gg_debug(GG_DEBUG_FUNCTION, "** gg_change_status_descr_time(%p, %d, \"%s\", %d);\n", sess, status, descr, time); | |
1172 | |
1173 if (!sess || !descr || !time) { | |
1174 errno = EFAULT; | |
1175 return -1; | |
1176 } | |
1177 | |
1178 if (sess->state != GG_STATE_CONNECTED) { | |
1179 errno = ENOTCONN; | |
1180 return -1; | |
1181 } | |
1182 | |
1183 p.status = gg_fix32(status); | |
1184 | |
1185 sess->status = status; | |
1186 | |
1187 newtime = gg_fix32(time); | |
1188 | |
1189 return gg_send_packet(sess, GG_NEW_STATUS, &p, sizeof(p), descr, (strlen(descr) > GG_STATUS_DESCR_MAXSIZE) ? GG_STATUS_DESCR_MAXSIZE : strlen(descr), &newtime, sizeof(newtime), NULL); | |
1190 } | |
1191 | |
1192 /* | |
1193 * gg_logoff() | |
1194 * | |
1195 * wylogowuje użytkownika i zamyka połączenie, ale nie zwalnia pamięci. | |
1196 * | |
1197 * - sess - opis sesji | |
1198 */ | |
1199 void gg_logoff(struct gg_session *sess) | |
1200 { | |
1201 if (!sess) | |
1202 return; | |
1203 | |
1204 gg_debug(GG_DEBUG_FUNCTION, "** gg_logoff(%p);\n", sess); | |
1205 | |
1206 if (GG_S_NA(sess->status & ~GG_STATUS_FRIENDS_MASK)) | |
1207 gg_change_status(sess, GG_STATUS_NOT_AVAIL); | |
1208 | |
1209 #ifdef __GG_LIBGADU_HAVE_OPENSSL | |
1210 if (sess->ssl) | |
1211 SSL_shutdown(sess->ssl); | |
1212 #endif | |
1213 | |
1214 #ifdef __GG_LIBGADU_HAVE_PTHREAD | |
1215 if (sess->resolver) { | |
1216 pthread_cancel(*((pthread_t*) sess->resolver)); | |
1217 free(sess->resolver); | |
1218 sess->resolver = NULL; | |
1219 } | |
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
1220 #elif defined _WIN32 |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
1221 if (sess->resolver) { |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
1222 HANDLE h = sess->resolver; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
1223 TerminateThread(h, 0); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
1224 CloseHandle(h); |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
1225 sess->resolver = NULL; |
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
1226 } |
11360 | 1227 #else |
1228 if (sess->pid != -1) { | |
1229 waitpid(sess->pid, NULL, WNOHANG); | |
1230 sess->pid = -1; | |
1231 } | |
1232 #endif | |
1233 | |
1234 if (sess->fd != -1) { | |
1235 shutdown(sess->fd, SHUT_RDWR); | |
1236 close(sess->fd); | |
1237 sess->fd = -1; | |
1238 } | |
1239 } | |
1240 | |
1241 /* | |
1242 * gg_image_request() | |
1243 * | |
1244 * wysyła żądanie wysłania obrazka o podanych parametrach. | |
1245 * | |
1246 * - sess - opis sesji | |
1247 * - recipient - numer adresata | |
1248 * - size - rozmiar obrazka | |
1249 * - crc32 - suma kontrolna obrazka | |
1250 * | |
1251 * 0/-1 | |
1252 */ | |
1253 int gg_image_request(struct gg_session *sess, uin_t recipient, int size, uint32_t crc32) | |
1254 { | |
1255 struct gg_send_msg s; | |
1256 struct gg_msg_image_request r; | |
1257 char dummy = 0; | |
1258 int res; | |
1259 | |
1260 gg_debug(GG_DEBUG_FUNCTION, "** gg_image_request(%p, %d, %u, 0x%.4x);\n", sess, recipient, size, crc32); | |
1261 | |
1262 if (!sess) { | |
1263 errno = EFAULT; | |
1264 return -1; | |
1265 } | |
1266 | |
1267 if (sess->state != GG_STATE_CONNECTED) { | |
1268 errno = ENOTCONN; | |
1269 return -1; | |
1270 } | |
1271 | |
1272 if (size < 0) { | |
1273 errno = EINVAL; | |
1274 return -1; | |
1275 } | |
1276 | |
1277 s.recipient = gg_fix32(recipient); | |
1278 s.seq = gg_fix32(0); | |
1279 s.msgclass = gg_fix32(GG_CLASS_MSG); | |
1280 | |
1281 r.flag = 0x04; | |
1282 r.size = gg_fix32(size); | |
1283 r.crc32 = gg_fix32(crc32); | |
1284 | |
1285 res = gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), &dummy, 1, &r, sizeof(r), NULL); | |
1286 | |
1287 if (!res) { | |
1288 struct gg_image_queue *q = malloc(sizeof(*q)); | |
1289 char *buf; | |
1290 | |
1291 if (!q) { | |
1292 gg_debug(GG_DEBUG_MISC, "// gg_image_request() not enough memory for image queue\n"); | |
1293 return -1; | |
1294 } | |
1295 | |
1296 buf = malloc(size); | |
1297 if (size && !buf) | |
1298 { | |
1299 gg_debug(GG_DEBUG_MISC, "// gg_image_request() not enough memory for image\n"); | |
1300 free(q); | |
1301 return -1; | |
1302 } | |
1303 | |
1304 memset(q, 0, sizeof(*q)); | |
1305 | |
1306 q->sender = recipient; | |
1307 q->size = size; | |
1308 q->crc32 = crc32; | |
1309 q->image = buf; | |
1310 | |
1311 if (!sess->images) | |
1312 sess->images = q; | |
1313 else { | |
1314 struct gg_image_queue *qq; | |
1315 | |
1316 for (qq = sess->images; qq->next; qq = qq->next) | |
1317 ; | |
1318 | |
1319 qq->next = q; | |
1320 } | |
1321 } | |
1322 | |
1323 return res; | |
1324 } | |
1325 | |
1326 /* | |
1327 * gg_image_reply() | |
1328 * | |
1329 * wysyła żądany obrazek. | |
1330 * | |
1331 * - sess - opis sesji | |
1332 * - recipient - numer adresata | |
1333 * - filename - nazwa pliku | |
1334 * - image - bufor z obrazkiem | |
1335 * - size - rozmiar obrazka | |
1336 * | |
1337 * 0/-1 | |
1338 */ | |
1339 int gg_image_reply(struct gg_session *sess, uin_t recipient, const char *filename, const char *image, int size) | |
1340 { | |
1341 struct gg_msg_image_reply *r; | |
1342 struct gg_send_msg s; | |
1343 const char *tmp; | |
1344 char buf[1910]; | |
1345 int res = -1; | |
1346 | |
1347 gg_debug(GG_DEBUG_FUNCTION, "** gg_image_reply(%p, %d, \"%s\", %p, %d);\n", sess, recipient, filename, image, size); | |
1348 | |
1349 if (!sess || !filename || !image) { | |
1350 errno = EFAULT; | |
1351 return -1; | |
1352 } | |
1353 | |
1354 if (sess->state != GG_STATE_CONNECTED) { | |
1355 errno = ENOTCONN; | |
1356 return -1; | |
1357 } | |
1358 | |
1359 if (size < 0) { | |
1360 errno = EINVAL; | |
1361 return -1; | |
1362 } | |
1363 | |
1364 /* wytnij ścieżki, zostaw tylko nazwę pliku */ | |
1365 while ((tmp = strrchr(filename, '/')) || (tmp = strrchr(filename, '\\'))) | |
1366 filename = tmp + 1; | |
1367 | |
1368 if (strlen(filename) < 1 || strlen(filename) > 1024) { | |
1369 errno = EINVAL; | |
1370 return -1; | |
1371 } | |
1372 | |
1373 s.recipient = gg_fix32(recipient); | |
1374 s.seq = gg_fix32(0); | |
1375 s.msgclass = gg_fix32(GG_CLASS_MSG); | |
1376 | |
1377 buf[0] = 0; | |
1378 r = (void*) &buf[1]; | |
1379 | |
1380 r->flag = 0x05; | |
1381 r->size = gg_fix32(size); | |
1382 r->crc32 = gg_fix32(gg_crc32(0, image, size)); | |
1383 | |
1384 while (size > 0) { | |
1385 int buflen, chunklen; | |
1386 | |
1387 /* \0 + struct gg_msg_image_reply */ | |
1388 buflen = sizeof(struct gg_msg_image_reply) + 1; | |
1389 | |
1390 /* w pierwszym kawałku jest nazwa pliku */ | |
1391 if (r->flag == 0x05) { | |
1392 strcpy(buf + buflen, filename); | |
1393 buflen += strlen(filename) + 1; | |
1394 } | |
1395 | |
1396 chunklen = (size >= sizeof(buf) - buflen) ? (sizeof(buf) - buflen) : size; | |
1397 | |
1398 memcpy(buf + buflen, image, chunklen); | |
1399 size -= chunklen; | |
1400 image += chunklen; | |
1401 | |
1402 res = gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), buf, buflen + chunklen, NULL); | |
1403 | |
1404 if (res == -1) | |
1405 break; | |
1406 | |
1407 r->flag = 0x06; | |
1408 } | |
1409 | |
1410 return res; | |
1411 } | |
1412 | |
1413 /* | |
1414 * gg_send_message_ctcp() | |
1415 * | |
1416 * wysyła wiadomość do innego użytkownika. zwraca losowy numer | |
1417 * sekwencyjny, który można zignorować albo wykorzystać do potwierdzenia. | |
1418 * | |
1419 * - sess - opis sesji | |
1420 * - msgclass - rodzaj wiadomości | |
1421 * - recipient - numer adresata | |
1422 * - message - treść wiadomości | |
1423 * - message_len - długość | |
1424 * | |
1425 * numer sekwencyjny wiadomości lub -1 w przypadku błędu. | |
1426 */ | |
1427 int gg_send_message_ctcp(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message, int message_len) | |
1428 { | |
1429 struct gg_send_msg s; | |
1430 | |
1431 gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message_ctcp(%p, %d, %u, ...);\n", sess, msgclass, recipient); | |
1432 | |
1433 if (!sess) { | |
1434 errno = EFAULT; | |
1435 return -1; | |
1436 } | |
1437 | |
1438 if (sess->state != GG_STATE_CONNECTED) { | |
1439 errno = ENOTCONN; | |
1440 return -1; | |
1441 } | |
1442 | |
1443 s.recipient = gg_fix32(recipient); | |
1444 s.seq = gg_fix32(0); | |
1445 s.msgclass = gg_fix32(msgclass); | |
1446 | |
1447 return gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), message, message_len, NULL); | |
1448 } | |
1449 | |
1450 /* | |
1451 * gg_send_message() | |
1452 * | |
1453 * wysyła wiadomość do innego użytkownika. zwraca losowy numer | |
1454 * sekwencyjny, który można zignorować albo wykorzystać do potwierdzenia. | |
1455 * | |
1456 * - sess - opis sesji | |
1457 * - msgclass - rodzaj wiadomości | |
1458 * - recipient - numer adresata | |
1459 * - message - treść wiadomości | |
1460 * | |
1461 * numer sekwencyjny wiadomości lub -1 w przypadku błędu. | |
1462 */ | |
1463 int gg_send_message(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message) | |
1464 { | |
1465 gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message(%p, %d, %u, %p)\n", sess, msgclass, recipient, message); | |
1466 | |
1467 return gg_send_message_richtext(sess, msgclass, recipient, message, NULL, 0); | |
1468 } | |
1469 | |
1470 /* | |
1471 * gg_send_message_richtext() | |
1472 * | |
1473 * wysyła kolorową wiadomość do innego użytkownika. zwraca losowy numer | |
1474 * sekwencyjny, który można zignorować albo wykorzystać do potwierdzenia. | |
1475 * | |
1476 * - sess - opis sesji | |
1477 * - msgclass - rodzaj wiadomości | |
1478 * - recipient - numer adresata | |
1479 * - message - treść wiadomości | |
1480 * - format - informacje o formatowaniu | |
1481 * - formatlen - długość informacji o formatowaniu | |
1482 * | |
1483 * numer sekwencyjny wiadomości lub -1 w przypadku błędu. | |
1484 */ | |
1485 int gg_send_message_richtext(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message, const unsigned char *format, int formatlen) | |
1486 { | |
1487 struct gg_send_msg s; | |
1488 | |
1489 gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message_richtext(%p, %d, %u, %p, %p, %d);\n", sess, msgclass, recipient, message, format, formatlen); | |
1490 | |
1491 if (!sess) { | |
1492 errno = EFAULT; | |
1493 return -1; | |
1494 } | |
1495 | |
1496 if (sess->state != GG_STATE_CONNECTED) { | |
1497 errno = ENOTCONN; | |
1498 return -1; | |
1499 } | |
1500 | |
1501 if (!message) { | |
1502 errno = EFAULT; | |
1503 return -1; | |
1504 } | |
1505 | |
1506 s.recipient = gg_fix32(recipient); | |
1507 if (!sess->seq) | |
1508 sess->seq = 0x01740000 | (rand() & 0xffff); | |
1509 s.seq = gg_fix32(sess->seq); | |
1510 s.msgclass = gg_fix32(msgclass); | |
1511 sess->seq += (rand() % 0x300) + 0x300; | |
1512 | |
1513 if (gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), message, strlen(message) + 1, format, formatlen, NULL) == -1) | |
1514 return -1; | |
1515 | |
1516 return gg_fix32(s.seq); | |
1517 } | |
1518 | |
1519 /* | |
1520 * gg_send_message_confer() | |
1521 * | |
1522 * wysyła wiadomość do kilku użytkownikow (konferencja). zwraca losowy numer | |
1523 * sekwencyjny, który można zignorować albo wykorzystać do potwierdzenia. | |
1524 * | |
1525 * - sess - opis sesji | |
1526 * - msgclass - rodzaj wiadomości | |
1527 * - recipients_count - ilość adresatów | |
1528 * - recipients - numerki adresatów | |
1529 * - message - treść wiadomości | |
1530 * | |
1531 * numer sekwencyjny wiadomości lub -1 w przypadku błędu. | |
1532 */ | |
1533 int gg_send_message_confer(struct gg_session *sess, int msgclass, int recipients_count, uin_t *recipients, const unsigned char *message) | |
1534 { | |
1535 gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message_confer(%p, %d, %d, %p, %p);\n", sess, msgclass, recipients_count, recipients, message); | |
1536 | |
1537 return gg_send_message_confer_richtext(sess, msgclass, recipients_count, recipients, message, NULL, 0); | |
1538 } | |
1539 | |
1540 /* | |
1541 * gg_send_message_confer_richtext() | |
1542 * | |
1543 * wysyła kolorową wiadomość do kilku użytkownikow (konferencja). zwraca | |
1544 * losowy numer sekwencyjny, który można zignorować albo wykorzystać do | |
1545 * potwierdzenia. | |
1546 * | |
1547 * - sess - opis sesji | |
1548 * - msgclass - rodzaj wiadomości | |
1549 * - recipients_count - ilość adresatów | |
1550 * - recipients - numerki adresatów | |
1551 * - message - treść wiadomości | |
1552 * - format - informacje o formatowaniu | |
1553 * - formatlen - długość informacji o formatowaniu | |
1554 * | |
1555 * numer sekwencyjny wiadomości lub -1 w przypadku błędu. | |
1556 */ | |
1557 int gg_send_message_confer_richtext(struct gg_session *sess, int msgclass, int recipients_count, uin_t *recipients, const unsigned char *message, const unsigned char *format, int formatlen) | |
1558 { | |
1559 struct gg_send_msg s; | |
1560 struct gg_msg_recipients r; | |
1561 int i, j, k; | |
1562 uin_t *recps; | |
1563 | |
1564 gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message_confer_richtext(%p, %d, %d, %p, %p, %p, %d);\n", sess, msgclass, recipients_count, recipients, message, format, formatlen); | |
1565 | |
1566 if (!sess) { | |
1567 errno = EFAULT; | |
1568 return -1; | |
1569 } | |
1570 | |
1571 if (sess->state != GG_STATE_CONNECTED) { | |
1572 errno = ENOTCONN; | |
1573 return -1; | |
1574 } | |
1575 | |
1576 if (!message || recipients_count <= 0 || recipients_count > 0xffff || !recipients) { | |
1577 errno = EINVAL; | |
1578 return -1; | |
1579 } | |
1580 | |
1581 r.flag = 0x01; | |
1582 r.count = gg_fix32(recipients_count - 1); | |
1583 | |
1584 if (!sess->seq) | |
1585 sess->seq = 0x01740000 | (rand() & 0xffff); | |
1586 s.seq = gg_fix32(sess->seq); | |
1587 s.msgclass = gg_fix32(msgclass); | |
1588 | |
1589 recps = malloc(sizeof(uin_t) * recipients_count); | |
1590 if (!recps) | |
1591 return -1; | |
1592 | |
1593 for (i = 0; i < recipients_count; i++) { | |
1594 | |
1595 s.recipient = gg_fix32(recipients[i]); | |
1596 | |
1597 for (j = 0, k = 0; j < recipients_count; j++) | |
1598 if (recipients[j] != recipients[i]) { | |
1599 recps[k] = gg_fix32(recipients[j]); | |
1600 k++; | |
1601 } | |
1602 | |
1603 if (!i) | |
1604 sess->seq += (rand() % 0x300) + 0x300; | |
1605 | |
1606 if (gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), message, strlen(message) + 1, &r, sizeof(r), recps, (recipients_count - 1) * sizeof(uin_t), format, formatlen, NULL) == -1) { | |
1607 free(recps); | |
1608 return -1; | |
1609 } | |
1610 } | |
1611 | |
1612 free(recps); | |
1613 | |
1614 return gg_fix32(s.seq); | |
1615 } | |
1616 | |
1617 /* | |
1618 * gg_ping() | |
1619 * | |
1620 * wysyła do serwera pakiet ping. | |
1621 * | |
1622 * - sess - opis sesji | |
1623 * | |
1624 * 0, -1. | |
1625 */ | |
1626 int gg_ping(struct gg_session *sess) | |
1627 { | |
1628 gg_debug(GG_DEBUG_FUNCTION, "** gg_ping(%p);\n", sess); | |
1629 | |
1630 if (!sess) { | |
1631 errno = EFAULT; | |
1632 return -1; | |
1633 } | |
1634 | |
1635 if (sess->state != GG_STATE_CONNECTED) { | |
1636 errno = ENOTCONN; | |
1637 return -1; | |
1638 } | |
1639 | |
1640 return gg_send_packet(sess, GG_PING, NULL); | |
1641 } | |
1642 | |
1643 /* | |
1644 * gg_notify_ex() | |
1645 * | |
1646 * wysyła serwerowi listę kontaktów (wraz z odpowiadającymi im typami userów), | |
1647 * dzięki czemu wie, czyj stan nas interesuje. | |
1648 * | |
1649 * - sess - opis sesji | |
1650 * - userlist - wskaźnik do tablicy numerów | |
1651 * - types - wskaźnik do tablicy typów użytkowników | |
1652 * - count - ilość numerków | |
1653 * | |
1654 * 0, -1. | |
1655 */ | |
1656 int gg_notify_ex(struct gg_session *sess, uin_t *userlist, char *types, int count) | |
1657 { | |
1658 struct gg_notify *n; | |
1659 uin_t *u; | |
1660 char *t; | |
1661 int i, res = 0; | |
1662 | |
1663 gg_debug(GG_DEBUG_FUNCTION, "** gg_notify_ex(%p, %p, %p, %d);\n", sess, userlist, types, count); | |
1664 | |
1665 if (!sess) { | |
1666 errno = EFAULT; | |
1667 return -1; | |
1668 } | |
1669 | |
1670 if (sess->state != GG_STATE_CONNECTED) { | |
1671 errno = ENOTCONN; | |
1672 return -1; | |
1673 } | |
1674 | |
1675 if (!userlist || !count) | |
1676 return gg_send_packet(sess, GG_LIST_EMPTY, NULL); | |
1677 | |
1678 while (count > 0) { | |
1679 int part_count, packet_type; | |
1680 | |
1681 if (count > 400) { | |
1682 part_count = 400; | |
1683 packet_type = GG_NOTIFY_FIRST; | |
1684 } else { | |
1685 part_count = count; | |
1686 packet_type = GG_NOTIFY_LAST; | |
1687 } | |
1688 | |
1689 if (!(n = (struct gg_notify*) malloc(sizeof(*n) * part_count))) | |
1690 return -1; | |
1691 | |
1692 for (u = userlist, t = types, i = 0; i < part_count; u++, t++, i++) { | |
1693 n[i].uin = gg_fix32(*u); | |
1694 n[i].dunno1 = *t; | |
1695 } | |
1696 | |
1697 if (gg_send_packet(sess, packet_type, n, sizeof(*n) * part_count, NULL) == -1) { | |
1698 free(n); | |
1699 res = -1; | |
1700 break; | |
1701 } | |
1702 | |
1703 count -= part_count; | |
1704 userlist += part_count; | |
1705 types += part_count; | |
1706 | |
1707 free(n); | |
1708 } | |
1709 | |
1710 return res; | |
1711 } | |
1712 | |
1713 /* | |
1714 * gg_notify() | |
1715 * | |
1716 * wysyła serwerowi listę kontaktów, dzięki czemu wie, czyj stan nas | |
1717 * interesuje. | |
1718 * | |
1719 * - sess - opis sesji | |
1720 * - userlist - wskaźnik do tablicy numerów | |
1721 * - count - ilość numerków | |
1722 * | |
1723 * 0, -1. | |
1724 */ | |
1725 int gg_notify(struct gg_session *sess, uin_t *userlist, int count) | |
1726 { | |
1727 struct gg_notify *n; | |
1728 uin_t *u; | |
1729 int i, res = 0; | |
1730 | |
1731 gg_debug(GG_DEBUG_FUNCTION, "** gg_notify(%p, %p, %d);\n", sess, userlist, count); | |
1732 | |
1733 if (!sess) { | |
1734 errno = EFAULT; | |
1735 return -1; | |
1736 } | |
1737 | |
1738 if (sess->state != GG_STATE_CONNECTED) { | |
1739 errno = ENOTCONN; | |
1740 return -1; | |
1741 } | |
1742 | |
1743 if (!userlist || !count) | |
1744 return gg_send_packet(sess, GG_LIST_EMPTY, NULL); | |
1745 | |
1746 while (count > 0) { | |
1747 int part_count, packet_type; | |
1748 | |
1749 if (count > 400) { | |
1750 part_count = 400; | |
1751 packet_type = GG_NOTIFY_FIRST; | |
1752 } else { | |
1753 part_count = count; | |
1754 packet_type = GG_NOTIFY_LAST; | |
1755 } | |
1756 | |
1757 if (!(n = (struct gg_notify*) malloc(sizeof(*n) * part_count))) | |
1758 return -1; | |
1759 | |
1760 for (u = userlist, i = 0; i < part_count; u++, i++) { | |
1761 n[i].uin = gg_fix32(*u); | |
1762 n[i].dunno1 = GG_USER_NORMAL; | |
1763 } | |
1764 | |
1765 if (gg_send_packet(sess, packet_type, n, sizeof(*n) * part_count, NULL) == -1) { | |
1766 res = -1; | |
1767 free(n); | |
1768 break; | |
1769 } | |
1770 | |
1771 free(n); | |
1772 | |
1773 userlist += part_count; | |
1774 count -= part_count; | |
1775 } | |
1776 | |
1777 return res; | |
1778 } | |
1779 | |
1780 /* | |
1781 * gg_add_notify_ex() | |
1782 * | |
1783 * dodaje do listy kontaktów dany numer w trakcie połączenia. | |
1784 * dodawanemu użytkownikowi określamy jego typ (patrz protocol.html) | |
1785 * | |
1786 * - sess - opis sesji | |
1787 * - uin - numer | |
1788 * - type - typ | |
1789 * | |
1790 * 0, -1. | |
1791 */ | |
1792 int gg_add_notify_ex(struct gg_session *sess, uin_t uin, char type) | |
1793 { | |
1794 struct gg_add_remove a; | |
1795 | |
1796 gg_debug(GG_DEBUG_FUNCTION, "** gg_add_notify_ex(%p, %u, %d);\n", sess, uin, type); | |
1797 | |
1798 if (!sess) { | |
1799 errno = EFAULT; | |
1800 return -1; | |
1801 } | |
1802 | |
1803 if (sess->state != GG_STATE_CONNECTED) { | |
1804 errno = ENOTCONN; | |
1805 return -1; | |
1806 } | |
1807 | |
1808 a.uin = gg_fix32(uin); | |
1809 a.dunno1 = type; | |
1810 | |
1811 return gg_send_packet(sess, GG_ADD_NOTIFY, &a, sizeof(a), NULL); | |
1812 } | |
1813 | |
1814 /* | |
1815 * gg_add_notify() | |
1816 * | |
1817 * dodaje do listy kontaktów dany numer w trakcie połączenia. | |
1818 * | |
1819 * - sess - opis sesji | |
1820 * - uin - numer | |
1821 * | |
1822 * 0, -1. | |
1823 */ | |
1824 int gg_add_notify(struct gg_session *sess, uin_t uin) | |
1825 { | |
1826 return gg_add_notify_ex(sess, uin, GG_USER_NORMAL); | |
1827 } | |
1828 | |
1829 /* | |
1830 * gg_remove_notify_ex() | |
1831 * | |
1832 * usuwa z listy kontaktów w trakcie połączenia. | |
1833 * usuwanemu użytkownikowi określamy jego typ (patrz protocol.html) | |
1834 * | |
1835 * - sess - opis sesji | |
1836 * - uin - numer | |
1837 * - type - typ | |
1838 * | |
1839 * 0, -1. | |
1840 */ | |
1841 int gg_remove_notify_ex(struct gg_session *sess, uin_t uin, char type) | |
1842 { | |
1843 struct gg_add_remove a; | |
1844 | |
1845 gg_debug(GG_DEBUG_FUNCTION, "** gg_remove_notify_ex(%p, %u, %d);\n", sess, uin, type); | |
1846 | |
1847 if (!sess) { | |
1848 errno = EFAULT; | |
1849 return -1; | |
1850 } | |
1851 | |
1852 if (sess->state != GG_STATE_CONNECTED) { | |
1853 errno = ENOTCONN; | |
1854 return -1; | |
1855 } | |
1856 | |
1857 a.uin = gg_fix32(uin); | |
1858 a.dunno1 = type; | |
1859 | |
1860 return gg_send_packet(sess, GG_REMOVE_NOTIFY, &a, sizeof(a), NULL); | |
1861 } | |
1862 | |
1863 /* | |
1864 * gg_remove_notify() | |
1865 * | |
1866 * usuwa z listy kontaktów w trakcie połączenia. | |
1867 * | |
1868 * - sess - opis sesji | |
1869 * - uin - numer | |
1870 * | |
1871 * 0, -1. | |
1872 */ | |
1873 int gg_remove_notify(struct gg_session *sess, uin_t uin) | |
1874 { | |
1875 return gg_remove_notify_ex(sess, uin, GG_USER_NORMAL); | |
1876 } | |
1877 | |
1878 /* | |
1879 * gg_userlist_request() | |
1880 * | |
1881 * wysyła żądanie/zapytanie listy kontaktów na serwerze. | |
1882 * | |
1883 * - sess - opis sesji | |
1884 * - type - rodzaj zapytania/żądania | |
1885 * - request - treść zapytania/żądania (może być NULL) | |
1886 * | |
1887 * 0, -1 | |
1888 */ | |
1889 int gg_userlist_request(struct gg_session *sess, char type, const char *request) | |
1890 { | |
1891 int len; | |
1892 | |
1893 if (!sess) { | |
1894 errno = EFAULT; | |
1895 return -1; | |
1896 } | |
1897 | |
1898 if (sess->state != GG_STATE_CONNECTED) { | |
1899 errno = ENOTCONN; | |
1900 return -1; | |
1901 } | |
1902 | |
1903 if (!request) { | |
1904 sess->userlist_blocks = 1; | |
1905 return gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), NULL); | |
1906 } | |
1907 | |
1908 len = strlen(request); | |
1909 | |
1910 sess->userlist_blocks = 0; | |
1911 | |
1912 while (len > 2047) { | |
1913 sess->userlist_blocks++; | |
1914 | |
1915 if (gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), request, 2047, NULL) == -1) | |
1916 return -1; | |
1917 | |
1918 if (type == GG_USERLIST_PUT) | |
1919 type = GG_USERLIST_PUT_MORE; | |
1920 | |
1921 request += 2047; | |
1922 len -= 2047; | |
1923 } | |
1924 | |
1925 sess->userlist_blocks++; | |
1926 | |
1927 return gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), request, len, NULL); | |
1928 } | |
1929 | |
1930 /* | |
1931 * Local variables: | |
1932 * c-indentation-style: k&r | |
1933 * c-basic-offset: 8 | |
1934 * indent-tabs-mode: notnil | |
1935 * End: | |
1936 * | |
1937 * vim: shiftwidth=8: | |
1938 */ |