Mercurial > pidgin
comparison libpurple/protocols/gg/lib/libgadu.c @ 29538:6359fde67f4c
Update our internal libgadu to 1.9.0-rc2. This does not yet build on Windows.
Refs #10542. The Windows build errors are the only reason this isn't on
`im.pidgin.pidgin` already.
author | John Bailey <rekkanoryo@rekkanoryo.org> |
---|---|
date | Sun, 21 Feb 2010 16:52:42 +0000 |
parents | 259bbfb423d4 |
children | db6735e579f8 |
comparison
equal
deleted
inserted
replaced
29474:551253814063 | 29538:6359fde67f4c |
---|---|
1 /* $Id: libgadu.c 16856 2006-08-19 01:13:25Z evands $ */ | 1 /* $Id: libgadu.c 878 2009-11-16 23:48:19Z wojtekka $ */ |
2 | 2 |
3 /* | 3 /* |
4 * (C) Copyright 2001-2003 Wojtek Kaniewski <wojtekka@irc.pl> | 4 * (C) Copyright 2001-2009 Wojtek Kaniewski <wojtekka@irc.pl> |
5 * Robert J. Wo糿y <speedy@ziew.org> | 5 * Robert J. Wo藕ny <speedy@ziew.org> |
6 * Arkadiusz Mi秌iewicz <arekm@pld-linux.org> | 6 * Arkadiusz Mi艣kiewicz <arekm@pld-linux.org> |
7 * Tomasz Chili駍ki <chilek@chilan.com> | 7 * Tomasz Chili艅ski <chilek@chilan.com> |
8 * Adam Wysocki <gophi@ekg.chmurka.net> | |
8 * | 9 * |
9 * This program is free software; you can redistribute it and/or modify | 10 * 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 * it under the terms of the GNU Lesser General Public License Version |
11 * 2.1 as published by the Free Software Foundation. | 12 * 2.1 as published by the Free Software Foundation. |
12 * | 13 * |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 * GNU Lesser General Public License for more details. | 17 * GNU Lesser General Public License for more details. |
17 * | 18 * |
18 * You should have received a copy of the GNU Lesser General Public | 19 * 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 * License along with this program; if not, write to the Free Software |
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, | 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, |
21 * USA. | 22 * USA. |
22 */ | 23 */ |
23 | 24 |
24 #include "libgadu.h" | 25 /** |
26 * \file libgadu.c | |
27 * | |
28 * \brief G艂贸wny modu艂 biblioteki | |
29 */ | |
25 | 30 |
26 #include <sys/types.h> | 31 #include <sys/types.h> |
27 #ifndef _WIN32 | |
28 #include <sys/wait.h> | |
29 #include <sys/socket.h> | 32 #include <sys/socket.h> |
30 #include <netinet/in.h> | 33 #include <netinet/in.h> |
31 #include <arpa/inet.h> | 34 #include <arpa/inet.h> |
32 #ifdef sun | 35 #ifdef sun |
33 # include <sys/filio.h> | 36 # include <sys/filio.h> |
34 #endif | 37 #endif |
35 #else | 38 |
36 #include <io.h> | 39 #include "compat.h" |
37 #include <fcntl.h> | 40 #include "libgadu.h" |
41 #include "protocol.h" | |
42 #include "resolver.h" | |
43 #include "libgadu-internal.h" | |
44 | |
38 #include <errno.h> | 45 #include <errno.h> |
39 #define SHUT_RDWR SD_BOTH | |
40 #endif | |
41 | |
42 #include "libgadu-config.h" | |
43 | |
44 #include <errno.h> | |
45 #ifndef _WIN32 | |
46 #include <netdb.h> | 46 #include <netdb.h> |
47 #endif | |
48 #ifdef __GG_LIBGADU_HAVE_PTHREAD | |
49 # include <pthread.h> | |
50 #endif | |
51 #include <stdarg.h> | 47 #include <stdarg.h> |
52 #include <stdio.h> | 48 #include <stdio.h> |
53 #include <stdlib.h> | 49 #include <stdlib.h> |
54 #include <string.h> | 50 #include <string.h> |
51 #include <signal.h> | |
52 #include <time.h> | |
55 #include <unistd.h> | 53 #include <unistd.h> |
56 #ifdef __GG_LIBGADU_HAVE_OPENSSL | 54 #ifdef GG_CONFIG_HAVE_OPENSSL |
57 # include <openssl/err.h> | 55 # include <openssl/err.h> |
58 # include <openssl/rand.h> | 56 # include <openssl/rand.h> |
59 #endif | 57 #endif |
60 | 58 |
61 #include "compat.h" | 59 #define GG_LIBGADU_VERSION "1.9.0-rc2" |
62 | 60 |
61 /** | |
62 * Poziom rejestracji informacji odpluskwiaj膮cych. Zmienna jest mask膮 bitow膮 | |
63 * sk艂adaj膮c膮 si臋 ze sta艂ych \c GG_DEBUG_... | |
64 * | |
65 * \ingroup debug | |
66 */ | |
63 int gg_debug_level = 0; | 67 int gg_debug_level = 0; |
68 | |
69 /** | |
70 * Funkcja, do kt贸rej s膮 przekazywane informacje odpluskwiaj膮ce. Je艣li zar贸wno | |
71 * ten \c gg_debug_handler, jak i \c gg_debug_handler_session, s膮 r贸wne | |
72 * \c NULL, informacje s膮 wysy艂ane do standardowego wyj艣cia b艂臋du (\c stderr). | |
73 * | |
74 * \param level Poziom rejestracji | |
75 * \param format Format wiadomo艣ci (zgodny z \c printf) | |
76 * \param ap Lista argument贸w (zgodna z \c printf) | |
77 * | |
78 * \note Funkcja jest przes艂aniana przez \c gg_debug_handler_session. | |
79 * | |
80 * \ingroup debug | |
81 */ | |
64 void (*gg_debug_handler)(int level, const char *format, va_list ap) = NULL; | 82 void (*gg_debug_handler)(int level, const char *format, va_list ap) = NULL; |
65 | 83 |
84 /** | |
85 * Funkcja, do kt贸rej s膮 przekazywane informacje odpluskwiaj膮ce. Je艣li zar贸wno | |
86 * ten \c gg_debug_handler, jak i \c gg_debug_handler_session, s膮 r贸wne | |
87 * \c NULL, informacje s膮 wysy艂ane do standardowego wyj艣cia b艂臋du. | |
88 * | |
89 * \param sess Sesja kt贸rej dotyczy informacja lub \c NULL | |
90 * \param level Poziom rejestracji | |
91 * \param format Format wiadomo艣ci (zgodny z \c printf) | |
92 * \param ap Lista argument贸w (zgodna z \c printf) | |
93 * | |
94 * \note Funkcja przes艂ania przez \c gg_debug_handler_session. | |
95 * | |
96 * \ingroup debug | |
97 */ | |
98 void (*gg_debug_handler_session)(struct gg_session *sess, int level, const char *format, va_list ap) = NULL; | |
99 | |
100 /** | |
101 * Port gniazda nas艂uchuj膮cego dla po艂膮cze艅 bezpo艣rednich. | |
102 * | |
103 * \ingroup ip | |
104 */ | |
66 int gg_dcc_port = 0; | 105 int gg_dcc_port = 0; |
106 | |
107 /** | |
108 * Adres IP gniazda nas艂uchuj膮cego dla po艂膮cze艅 bezpo艣rednich. | |
109 * | |
110 * \ingroup ip | |
111 */ | |
67 unsigned long gg_dcc_ip = 0; | 112 unsigned long gg_dcc_ip = 0; |
68 | 113 |
114 /** | |
115 * Adres lokalnego interfejsu IP, z kt贸rego wywo艂ywane s膮 wszystkie po艂膮czenia. | |
116 * | |
117 * \ingroup ip | |
118 */ | |
69 unsigned long gg_local_ip = 0; | 119 unsigned long gg_local_ip = 0; |
70 /* | 120 |
71 * zmienne opisuj眂e parametry proxy http. | 121 /** |
122 * Flaga w艂膮czenia po艂膮cze艅 przez serwer po艣rednicz膮cy. | |
123 * | |
124 * \ingroup proxy | |
125 */ | |
126 int gg_proxy_enabled = 0; | |
127 | |
128 /** | |
129 * Adres serwera po艣rednicz膮cego. | |
130 * | |
131 * \ingroup proxy | |
72 */ | 132 */ |
73 char *gg_proxy_host = NULL; | 133 char *gg_proxy_host = NULL; |
134 | |
135 /** | |
136 * Port serwera po艣rednicz膮cego. | |
137 * | |
138 * \ingroup proxy | |
139 */ | |
74 int gg_proxy_port = 0; | 140 int gg_proxy_port = 0; |
75 int gg_proxy_enabled = 0; | 141 |
142 /** | |
143 * Flaga u偶ywania serwera po艣rednicz膮cego jedynie dla us艂ug HTTP. | |
144 * | |
145 * \ingroup proxy | |
146 */ | |
76 int gg_proxy_http_only = 0; | 147 int gg_proxy_http_only = 0; |
148 | |
149 /** | |
150 * Nazwa u偶ytkownika do autoryzacji serwera po艣rednicz膮cego. | |
151 * | |
152 * \ingroup proxy | |
153 */ | |
77 char *gg_proxy_username = NULL; | 154 char *gg_proxy_username = NULL; |
155 | |
156 /** | |
157 * Has艂o u偶ytkownika do autoryzacji serwera po艣rednicz膮cego. | |
158 * | |
159 * \ingroup proxy | |
160 */ | |
78 char *gg_proxy_password = NULL; | 161 char *gg_proxy_password = NULL; |
79 | 162 |
80 #ifndef lint | 163 #ifndef DOXYGEN |
164 | |
165 #ifndef lint | |
81 static char rcsid[] | 166 static char rcsid[] |
82 #ifdef __GNUC__ | 167 #ifdef __GNUC__ |
83 __attribute__ ((unused)) | 168 __attribute__ ((unused)) |
84 #endif | 169 #endif |
85 = "$Id: libgadu.c 16856 2006-08-19 01:13:25Z evands $"; | 170 = "$Id: libgadu.c 878 2009-11-16 23:48:19Z wojtekka $"; |
86 #endif | |
87 | |
88 #ifdef _WIN32 | |
89 /** | |
90 * Deal with the fact that you can't select() on a win32 file fd. | |
91 * This makes it practically impossible to tie into purple's event loop. | |
92 * | |
93 * -This is thanks to Tor Lillqvist. | |
94 * XXX - Move this to where the rest of the the win32 compatiblity stuff goes when we push the changes back to libgadu. | |
95 */ | |
96 static int | |
97 socket_pipe (int *fds) | |
98 { | |
99 SOCKET temp, socket1 = -1, socket2 = -1; | |
100 struct sockaddr_in saddr; | |
101 int len; | |
102 u_long arg; | |
103 fd_set read_set, write_set; | |
104 struct timeval tv; | |
105 | |
106 temp = socket(AF_INET, SOCK_STREAM, 0); | |
107 | |
108 if (temp == INVALID_SOCKET) { | |
109 goto out0; | |
110 } | |
111 | |
112 arg = 1; | |
113 if (ioctlsocket(temp, FIONBIO, &arg) == SOCKET_ERROR) { | |
114 goto out0; | |
115 } | |
116 | |
117 memset(&saddr, 0, sizeof(saddr)); | |
118 saddr.sin_family = AF_INET; | |
119 saddr.sin_port = 0; | |
120 saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); | |
121 | |
122 if (bind(temp, (struct sockaddr *)&saddr, sizeof (saddr))) { | |
123 goto out0; | |
124 } | |
125 | |
126 if (listen(temp, 1) == SOCKET_ERROR) { | |
127 goto out0; | |
128 } | |
129 | |
130 len = sizeof(saddr); | |
131 if (getsockname(temp, (struct sockaddr *)&saddr, &len)) { | |
132 goto out0; | |
133 } | |
134 | |
135 socket1 = socket(AF_INET, SOCK_STREAM, 0); | |
136 | |
137 if (socket1 == INVALID_SOCKET) { | |
138 goto out0; | |
139 } | |
140 | |
141 arg = 1; | |
142 if (ioctlsocket(socket1, FIONBIO, &arg) == SOCKET_ERROR) { | |
143 goto out1; | |
144 } | |
145 | |
146 if (connect(socket1, (struct sockaddr *)&saddr, len) != SOCKET_ERROR || | |
147 WSAGetLastError() != WSAEWOULDBLOCK) { | |
148 goto out1; | |
149 } | |
150 | |
151 FD_ZERO(&read_set); | |
152 FD_SET(temp, &read_set); | |
153 | |
154 tv.tv_sec = 0; | |
155 tv.tv_usec = 0; | |
156 | |
157 if (select(0, &read_set, NULL, NULL, NULL) == SOCKET_ERROR) { | |
158 goto out1; | |
159 } | |
160 | |
161 if (!FD_ISSET(temp, &read_set)) { | |
162 goto out1; | |
163 } | |
164 | |
165 socket2 = accept(temp, (struct sockaddr *) &saddr, &len); | |
166 if (socket2 == INVALID_SOCKET) { | |
167 goto out1; | |
168 } | |
169 | |
170 FD_ZERO(&write_set); | |
171 FD_SET(socket1, &write_set); | |
172 | |
173 tv.tv_sec = 0; | |
174 tv.tv_usec = 0; | |
175 | |
176 if (select(0, NULL, &write_set, NULL, NULL) == SOCKET_ERROR) { | |
177 goto out2; | |
178 } | |
179 | |
180 if (!FD_ISSET(socket1, &write_set)) { | |
181 goto out2; | |
182 } | |
183 | |
184 arg = 0; | |
185 if (ioctlsocket(socket1, FIONBIO, &arg) == SOCKET_ERROR) { | |
186 goto out2; | |
187 } | |
188 | |
189 arg = 0; | |
190 if (ioctlsocket(socket2, FIONBIO, &arg) == SOCKET_ERROR) { | |
191 goto out2; | |
192 } | |
193 | |
194 fds[0] = socket1; | |
195 fds[1] = socket2; | |
196 | |
197 closesocket (temp); | |
198 | |
199 return 0; | |
200 | |
201 out2: | |
202 closesocket (socket2); | |
203 out1: | |
204 closesocket (socket1); | |
205 out0: | |
206 closesocket (temp); | |
207 errno = EIO; /* XXX */ | |
208 | |
209 return -1; | |
210 } | |
211 #endif | 171 #endif |
212 | 172 |
213 /* | 173 #endif /* DOXYGEN */ |
214 * gg_libgadu_version() | 174 |
215 * | 175 /** |
216 * zwraca wersj libgadu. | 176 * Zwraca wersj臋 biblioteki. |
217 * | 177 * |
218 * - brak | 178 * \return Wska藕nik na statyczny bufor z wersj膮 biblioteki. |
219 * | 179 * |
220 * wersja libgadu. | 180 * \ingroup version |
221 */ | 181 */ |
222 const char *gg_libgadu_version() | 182 const char *gg_libgadu_version() |
223 { | 183 { |
224 return GG_LIBGADU_VERSION; | 184 return GG_LIBGADU_VERSION; |
225 } | 185 } |
226 | 186 |
227 /* | 187 /** |
228 * gg_fix32() | 188 * \internal Zamienia kolejno艣膰 bajt贸w w 32-bitowym s艂owie. |
229 * | 189 * |
230 * zamienia kolejno舵 bajt體 w liczbie 32-bitowej tak, by odpowiada砤 | 190 * Ze wzgl臋du na little-endianowo艣膰 protoko艂u Gadu-Gadu, na maszynach |
231 * kolejno禼i bajt體 w protokole GG. ze wzgl阣u na LE-owo舵 serwera, | 191 * big-endianowych odwraca kolejno艣膰 bajt贸w w s艂owie. |
232 * zamienia tylko na maszynach BE-wych. | 192 * |
233 * | 193 * \param x Liczba do zamiany |
234 * - x - liczba do zamiany | 194 * |
235 * | 195 * \return Liczba z odpowiedni膮 kolejno艣ci膮 bajt贸w |
236 * liczba z odpowiedni kolejno禼i bajt體. | 196 * |
197 * \ingroup helper | |
237 */ | 198 */ |
238 uint32_t gg_fix32(uint32_t x) | 199 uint32_t gg_fix32(uint32_t x) |
239 { | 200 { |
240 #ifndef __GG_LIBGADU_BIGENDIAN | 201 #ifndef GG_CONFIG_BIGENDIAN |
241 return x; | 202 return x; |
242 #else | 203 #else |
243 return (uint32_t) | 204 return (uint32_t) |
244 (((x & (uint32_t) 0x000000ffU) << 24) | | 205 (((x & (uint32_t) 0x000000ffU) << 24) | |
245 ((x & (uint32_t) 0x0000ff00U) << 8) | | 206 ((x & (uint32_t) 0x0000ff00U) << 8) | |
246 ((x & (uint32_t) 0x00ff0000U) >> 8) | | 207 ((x & (uint32_t) 0x00ff0000U) >> 8) | |
247 ((x & (uint32_t) 0xff000000U) >> 24)); | 208 ((x & (uint32_t) 0xff000000U) >> 24)); |
248 #endif | 209 #endif |
249 } | 210 } |
250 | 211 |
251 /* | 212 /** |
252 * gg_fix16() | 213 * \internal Zamienia kolejno艣膰 bajt贸w w 16-bitowym s艂owie. |
253 * | 214 * |
254 * zamienia kolejno舵 bajt體 w liczbie 16-bitowej tak, by odpowiada砤 | 215 * Ze wzgl臋du na little-endianowo艣膰 protoko艂u Gadu-Gadu, na maszynach |
255 * kolejno禼i bajt體 w protokole GG. ze wzgl阣u na LE-owo舵 serwera, | 216 * big-endianowych zamienia kolejno艣膰 bajt贸w w s艂owie. |
256 * zamienia tylko na maszynach BE-wych. | 217 * |
257 * | 218 * \param x Liczba do zamiany |
258 * - x - liczba do zamiany | 219 * |
259 * | 220 * \return Liczba z odpowiedni膮 kolejno艣ci膮 bajt贸w |
260 * liczba z odpowiedni kolejno禼i bajt體. | 221 * |
222 * \ingroup helper | |
261 */ | 223 */ |
262 uint16_t gg_fix16(uint16_t x) | 224 uint16_t gg_fix16(uint16_t x) |
263 { | 225 { |
264 #ifndef __GG_LIBGADU_BIGENDIAN | 226 #ifndef GG_CONFIG_BIGENDIAN |
265 return x; | 227 return x; |
266 #else | 228 #else |
267 return (uint16_t) | 229 return (uint16_t) |
268 (((x & (uint16_t) 0x00ffU) << 8) | | 230 (((x & (uint16_t) 0x00ffU) << 8) | |
269 ((x & (uint16_t) 0xff00U) >> 8)); | 231 ((x & (uint16_t) 0xff00U) >> 8)); |
270 #endif | 232 #endif |
271 } | 233 } |
272 | 234 |
273 /* | 235 /** |
274 * gg_login_hash() // funkcja wewn阾rzna | 236 * \internal Liczy skr贸t z has艂a i ziarna. |
275 * | 237 * |
276 * liczy hash z has砤 i danego seeda. | 238 * \param password Has艂o |
277 * | 239 * \param seed Ziarno podane przez serwer |
278 * - password - has硂 do hashowania | 240 * |
279 * - seed - warto舵 podana przez serwer | 241 * \return Warto艣膰 skr贸tu |
280 * | |
281 * hash. | |
282 */ | 242 */ |
283 unsigned int gg_login_hash(const unsigned char *password, unsigned int seed) | 243 unsigned int gg_login_hash(const unsigned char *password, unsigned int seed) |
284 { | 244 { |
285 unsigned int x, y, z; | 245 unsigned int x, y, z; |
286 | 246 |
302 } | 262 } |
303 | 263 |
304 return y; | 264 return y; |
305 } | 265 } |
306 | 266 |
307 #ifndef _WIN32 | 267 /** |
308 | 268 * \internal Odbiera od serwera dane binarne. |
309 /* | 269 * |
310 * gg_resolve() // funkcja wewn阾rzna | 270 * Funkcja odbiera dane od serwera zajmuj膮c si臋 TLS w razie konieczno艣ci. |
311 * | 271 * |
312 * tworzy potok, forkuje si i w drugim procesie zaczyna resolvowa | 272 * \param sess Struktura sesji |
313 * podanego hosta. zapisuje w sesji deskryptor potoku. je秎i co tam | 273 * \param buf Bufor na danymi |
314 * b阣zie gotowego, znaczy, 縠 mo縩a wczyta struct in_addr. je秎i | 274 * \param length D艂ugo艣膰 bufora |
315 * nie znajdzie, zwraca INADDR_NONE. | 275 * |
316 * | 276 * \return To samo co funkcja systemowa \c read |
317 * - fd - wska糿ik gdzie wrzuci deskryptor | |
318 * - pid - gdzie wrzuci pid procesu potomnego | |
319 * - hostname - nazwa hosta do zresolvowania | |
320 * | |
321 * 0, -1. | |
322 */ | |
323 int gg_resolve(int *fd, int *pid, const char *hostname) | |
324 { | |
325 int pipes[2], res; | |
326 struct in_addr a; | |
327 int errno2; | |
328 | |
329 gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve(%p, %p, \"%s\");\n", fd, pid, hostname); | |
330 | |
331 if (!fd || !pid) { | |
332 errno = EFAULT; | |
333 return -1; | |
334 } | |
335 | |
336 if (pipe(pipes) == -1) | |
337 return -1; | |
338 | |
339 if ((res = fork()) == -1) { | |
340 errno2 = errno; | |
341 close(pipes[0]); | |
342 close(pipes[1]); | |
343 errno = errno2; | |
344 return -1; | |
345 } | |
346 | |
347 if (!res) { | |
348 if ((a.s_addr = inet_addr(hostname)) == INADDR_NONE) { | |
349 struct in_addr *hn; | |
350 | |
351 if (!(hn = gg_gethostbyname(hostname))) | |
352 a.s_addr = INADDR_NONE; | |
353 else { | |
354 a.s_addr = hn->s_addr; | |
355 free(hn); | |
356 } | |
357 } | |
358 | |
359 write(pipes[1], &a, sizeof(a)); | |
360 | |
361 _exit(0); | |
362 } | |
363 | |
364 close(pipes[1]); | |
365 | |
366 *fd = pipes[0]; | |
367 *pid = res; | |
368 | |
369 return 0; | |
370 } | |
371 #endif | |
372 | |
373 #ifdef __GG_LIBGADU_HAVE_PTHREAD | |
374 | |
375 struct gg_resolve_pthread_data { | |
376 char *hostname; | |
377 int fd; | |
378 }; | |
379 | |
380 static void *gg_resolve_pthread_thread(void *arg) | |
381 { | |
382 struct gg_resolve_pthread_data *d = arg; | |
383 struct in_addr a; | |
384 | |
385 pthread_detach(pthread_self()); | |
386 | |
387 if ((a.s_addr = inet_addr(d->hostname)) == INADDR_NONE) { | |
388 struct in_addr *hn; | |
389 | |
390 if (!(hn = gg_gethostbyname(d->hostname))) | |
391 a.s_addr = INADDR_NONE; | |
392 else { | |
393 a.s_addr = hn->s_addr; | |
394 free(hn); | |
395 } | |
396 } | |
397 | |
398 write(d->fd, &a, sizeof(a)); | |
399 close(d->fd); | |
400 | |
401 free(d->hostname); | |
402 d->hostname = NULL; | |
403 | |
404 free(d); | |
405 | |
406 pthread_exit(NULL); | |
407 | |
408 return NULL; /* 縠by kompilator nie marudzi */ | |
409 } | |
410 | |
411 /* | |
412 * gg_resolve_pthread() // funkcja wewn阾rzna | |
413 * | |
414 * tworzy potok, nowy w眛ek i w nim zaczyna resolvowa podanego hosta. | |
415 * zapisuje w sesji deskryptor potoku. je秎i co tam b阣zie gotowego, | |
416 * znaczy, 縠 mo縩a wczyta struct in_addr. je秎i nie znajdzie, zwraca | |
417 * INADDR_NONE. | |
418 * | |
419 * - fd - wska糿ik do zmiennej przechowuj眂ej desktyptor resolvera | |
420 * - resolver - wska糿ik do wska糿ika resolvera | |
421 * - hostname - nazwa hosta do zresolvowania | |
422 * | |
423 * 0, -1. | |
424 */ | |
425 int gg_resolve_pthread(int *fd, void **resolver, const char *hostname) | |
426 { | |
427 struct gg_resolve_pthread_data *d = NULL; | |
428 pthread_t *tmp; | |
429 int pipes[2], new_errno; | |
430 | |
431 gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve_pthread(%p, %p, \"%s\");\n", fd, resolver, hostname); | |
432 | |
433 if (!resolver || !fd || !hostname) { | |
434 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() invalid arguments\n"); | |
435 errno = EFAULT; | |
436 return -1; | |
437 } | |
438 | |
439 if (!(tmp = malloc(sizeof(pthread_t)))) { | |
440 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory for pthread id\n"); | |
441 return -1; | |
442 } | |
443 | |
444 if (pipe(pipes) == -1) { | |
445 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() unable to create pipes (errno=%d, %s)\n", errno, strerror(errno)); | |
446 free(tmp); | |
447 return -1; | |
448 } | |
449 | |
450 if (!(d = malloc(sizeof(*d)))) { | |
451 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory\n"); | |
452 new_errno = errno; | |
453 goto cleanup; | |
454 } | |
455 | |
456 d->hostname = NULL; | |
457 | |
458 if (!(d->hostname = strdup(hostname))) { | |
459 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory\n"); | |
460 new_errno = errno; | |
461 goto cleanup; | |
462 } | |
463 | |
464 d->fd = pipes[1]; | |
465 | |
466 if (pthread_create(tmp, NULL, gg_resolve_pthread_thread, d)) { | |
467 gg_debug(GG_DEBUG_MISC, "// gg_resolve_phread() unable to create thread\n"); | |
468 new_errno = errno; | |
469 goto cleanup; | |
470 } | |
471 | |
472 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() %p\n", tmp); | |
473 | |
474 *resolver = tmp; | |
475 | |
476 *fd = pipes[0]; | |
477 | |
478 return 0; | |
479 | |
480 cleanup: | |
481 if (d) { | |
482 free(d->hostname); | |
483 free(d); | |
484 } | |
485 | |
486 close(pipes[0]); | |
487 close(pipes[1]); | |
488 | |
489 free(tmp); | |
490 | |
491 errno = new_errno; | |
492 | |
493 return -1; | |
494 } | |
495 | |
496 #elif defined _WIN32 | |
497 | |
498 struct gg_resolve_win32thread_data { | |
499 char *hostname; | |
500 int fd; | |
501 }; | |
502 | |
503 static DWORD WINAPI gg_resolve_win32thread_thread(LPVOID arg) | |
504 { | |
505 struct gg_resolve_win32thread_data *d = arg; | |
506 struct in_addr a; | |
507 | |
508 if ((a.s_addr = inet_addr(d->hostname)) == INADDR_NONE) { | |
509 struct in_addr *hn; | |
510 | |
511 if (!(hn = gg_gethostbyname(d->hostname))) | |
512 a.s_addr = INADDR_NONE; | |
513 else { | |
514 a.s_addr = hn->s_addr; | |
515 free(hn); | |
516 } | |
517 } | |
518 | |
519 write(d->fd, &a, sizeof(a)); | |
520 close(d->fd); | |
521 | |
522 free(d->hostname); | |
523 d->hostname = NULL; | |
524 | |
525 free(d); | |
526 | |
527 return 0; | |
528 } | |
529 | |
530 | |
531 int gg_resolve_win32thread(int *fd, void **resolver, const char *hostname) | |
532 { | |
533 struct gg_resolve_win32thread_data *d = NULL; | |
534 HANDLE h; | |
535 DWORD dwTId; | |
536 int pipes[2], new_errno; | |
537 | |
538 gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve_win32thread(%p, %p, \"%s\");\n", fd, resolver, hostname); | |
539 | |
540 if (!resolver || !fd || !hostname) { | |
541 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() invalid arguments\n"); | |
542 errno = EFAULT; | |
543 return -1; | |
544 } | |
545 | |
546 if (socket_pipe(pipes) == -1) { | |
547 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() unable to create pipes (errno=%d, %s)\n", errno, strerror(errno)); | |
548 return -1; | |
549 } | |
550 | |
551 if (!(d = malloc(sizeof(*d)))) { | |
552 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() out of memory\n"); | |
553 new_errno = GetLastError(); | |
554 goto cleanup; | |
555 } | |
556 | |
557 d->hostname = NULL; | |
558 | |
559 if (!(d->hostname = strdup(hostname))) { | |
560 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() out of memory\n"); | |
561 new_errno = GetLastError(); | |
562 goto cleanup; | |
563 } | |
564 | |
565 d->fd = pipes[1]; | |
566 | |
567 h = CreateThread(NULL, 0, gg_resolve_win32thread_thread, | |
568 d, 0, &dwTId); | |
569 | |
570 if (h == NULL) { | |
571 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() unable to create thread\n"); | |
572 new_errno = GetLastError(); | |
573 goto cleanup; | |
574 } | |
575 | |
576 *resolver = h; | |
577 *fd = pipes[0]; | |
578 | |
579 return 0; | |
580 | |
581 cleanup: | |
582 if (d) { | |
583 free(d->hostname); | |
584 free(d); | |
585 } | |
586 | |
587 close(pipes[0]); | |
588 close(pipes[1]); | |
589 | |
590 errno = new_errno; | |
591 | |
592 return -1; | |
593 | |
594 } | |
595 #endif | |
596 | |
597 /* | |
598 * gg_read() // funkcja pomocnicza | |
599 * | |
600 * czyta z gniazda okre秎on ilo舵 bajt體. bierze pod uwag, czy mamy | |
601 * po潮czenie zwyk砮 czy TLS. | |
602 * | |
603 * - sess - sesja, | |
604 * - buf - bufor, | |
605 * - length - ilo舵 bajt體, | |
606 * | |
607 * takie same warto禼i jak read(). | |
608 */ | 277 */ |
609 int gg_read(struct gg_session *sess, char *buf, int length) | 278 int gg_read(struct gg_session *sess, char *buf, int length) |
610 { | 279 { |
611 int res; | 280 int res; |
612 | 281 |
613 #ifdef __GG_LIBGADU_HAVE_OPENSSL | 282 #ifdef GG_CONFIG_HAVE_OPENSSL |
614 if (sess->ssl) { | 283 if (sess->ssl) { |
615 int err; | 284 int err; |
616 | 285 |
617 res = SSL_read(sess->ssl, buf, length); | 286 res = SSL_read(sess->ssl, buf, length); |
618 | 287 |
629 res = read(sess->fd, buf, length); | 298 res = read(sess->fd, buf, length); |
630 | 299 |
631 return res; | 300 return res; |
632 } | 301 } |
633 | 302 |
634 /* | 303 /** |
635 * gg_write() // funkcja pomocnicza | 304 * \internal Wysy艂a do serwera dane binarne. |
636 * | 305 * |
637 * zapisuje do gniazda okre秎on ilo舵 bajt體. bierze pod uwag, czy mamy | 306 * Funkcja wysy艂a dane do serwera zajmuj膮c si臋 TLS w razie konieczno艣ci. |
638 * po潮czenie zwyk砮 czy TLS. | 307 * |
639 * | 308 * \param sess Struktura sesji |
640 * - sess - sesja, | 309 * \param buf Bufor z danymi |
641 * - buf - bufor, | 310 * \param length D艂ugo艣膰 bufora |
642 * - length - ilo舵 bajt體, | 311 * |
643 * | 312 * \return To samo co funkcja systemowa \c write |
644 * takie same warto禼i jak write(). | |
645 */ | 313 */ |
646 int gg_write(struct gg_session *sess, const char *buf, int length) | 314 int gg_write(struct gg_session *sess, const char *buf, int length) |
647 { | 315 { |
648 int res = 0; | 316 int res = 0; |
649 | 317 |
650 #ifdef __GG_LIBGADU_HAVE_OPENSSL | 318 #ifdef GG_CONFIG_HAVE_OPENSSL |
651 if (sess->ssl) { | 319 if (sess->ssl) { |
652 int err; | 320 int err; |
653 | 321 |
654 res = SSL_write(sess->ssl, buf, length); | 322 res = SSL_write(sess->ssl, buf, length); |
655 | 323 |
662 return -1; | 330 return -1; |
663 } | 331 } |
664 } else | 332 } else |
665 #endif | 333 #endif |
666 { | 334 { |
667 int written = 0; | 335 if (!sess->async) { |
668 | 336 int written = 0; |
669 while (written < length) { | 337 |
670 res = write(sess->fd, buf + written, length - written); | 338 while (written < length) { |
671 | 339 res = write(sess->fd, buf + written, length - written); |
672 if (res == -1) { | 340 |
673 if (errno == EAGAIN) | 341 if (res == -1) { |
342 if (errno != EINTR) | |
343 break; | |
344 | |
674 continue; | 345 continue; |
675 else | 346 } |
676 break; | 347 |
677 } else { | |
678 written += res; | 348 written += res; |
679 res = written; | 349 res = written; |
680 } | 350 } |
351 } else { | |
352 if (!sess->send_buf) | |
353 res = write(sess->fd, buf, length); | |
354 else | |
355 res = 0; | |
356 | |
357 if (res == -1) { | |
358 if (errno != EAGAIN) | |
359 return res; | |
360 | |
361 res = 0; | |
362 } | |
363 | |
364 if (res < length) { | |
365 char *tmp; | |
366 | |
367 if (!(tmp = realloc(sess->send_buf, sess->send_left + length - res))) { | |
368 errno = ENOMEM; | |
369 return -1; | |
370 } | |
371 | |
372 sess->send_buf = tmp; | |
373 | |
374 memcpy(sess->send_buf + sess->send_left, buf + res, length - res); | |
375 | |
376 sess->send_left += length - res; | |
377 } | |
681 } | 378 } |
682 } | 379 } |
683 | 380 |
684 return res; | 381 return res; |
685 } | 382 } |
686 | 383 |
687 /* | 384 /** |
688 * gg_recv_packet() // funkcja wewn阾rzna | 385 * \internal Odbiera pakiet od serwera. |
689 * | 386 * |
690 * odbiera jeden pakiet i zwraca wska糿ik do niego. pami赕 po nim | 387 * Funkcja odczytuje nag艂贸wek pakietu, a nast臋pnie jego zawarto艣膰 i zwraca |
691 * nale縴 zwolni za pomoc free(). | 388 * w zaalokowanym buforze. |
692 * | 389 * |
693 * - sess - opis sesji | 390 * Przy po艂膮czeniach asynchronicznych, funkcja mo偶e nie by膰 w stanie |
694 * | 391 * skompletowa膰 ca艂ego pakietu -- w takim przypadku zwr贸ci -1, a kodem b艂臋du |
695 * w przypadku b酬du NULL, kod b酬du w errno. nale縴 zwr骳i uwag, 縠 gdy | 392 * b臋dzie \c EAGAIN. |
696 * po潮czenie jest nieblokuj眂e, a kod b酬du wynosi EAGAIN, nie uda硂 si | 393 * |
697 * odczyta ca砮go pakietu i nie nale縴 tego traktowa jako b潮d. | 394 * \param sess Struktura sesji |
395 * | |
396 * \return Wska藕nik do zaalokowanego bufora | |
698 */ | 397 */ |
699 void *gg_recv_packet(struct gg_session *sess) | 398 void *gg_recv_packet(struct gg_session *sess) |
700 { | 399 { |
701 struct gg_header h; | 400 struct gg_header h; |
702 char *buf = NULL; | 401 char *buf = NULL; |
703 int ret = 0, offset, size = 0; | 402 int ret = 0; |
704 | 403 unsigned int offset, size = 0; |
705 gg_debug(GG_DEBUG_FUNCTION, "** gg_recv_packet(%p);\n", sess); | 404 |
706 | 405 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_recv_packet(%p);\n", sess); |
406 | |
707 if (!sess) { | 407 if (!sess) { |
708 errno = EFAULT; | 408 errno = EFAULT; |
709 return NULL; | 409 return NULL; |
710 } | 410 } |
711 | 411 |
712 if (sess->recv_left < 1) { | 412 if (sess->recv_left < 1) { |
713 if (sess->header_buf) { | 413 if (sess->header_buf) { |
714 memcpy(&h, sess->header_buf, sess->header_done); | 414 memcpy(&h, sess->header_buf, sess->header_done); |
715 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv: resuming last read (%d bytes left)\n", sizeof(h) - sess->header_done); | 415 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv: resuming last read (%d bytes left)\n", sizeof(h) - sess->header_done); |
716 free(sess->header_buf); | 416 free(sess->header_buf); |
717 sess->header_buf = NULL; | 417 sess->header_buf = NULL; |
718 } else | 418 } else |
719 sess->header_done = 0; | 419 sess->header_done = 0; |
720 | 420 |
721 while (sess->header_done < sizeof(h)) { | 421 while (sess->header_done < sizeof(h)) { |
722 ret = gg_read(sess, (char*) &h + sess->header_done, sizeof(h) - sess->header_done); | 422 ret = gg_read(sess, (char*) &h + sess->header_done, sizeof(h) - sess->header_done); |
723 | 423 |
724 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); | 424 gg_debug_session(sess, 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); |
725 | 425 |
726 if (!ret) { | 426 if (!ret) { |
727 errno = ECONNRESET; | 427 errno = ECONNRESET; |
728 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: connection broken\n"); | 428 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: connection broken\n"); |
729 return NULL; | 429 return NULL; |
730 } | 430 } |
731 | 431 |
732 if (ret == -1) { | 432 if (ret == -1) { |
733 if (errno == EINTR) { | 433 if (errno == EINTR) { |
734 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() interrupted system call, resuming\n"); | 434 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() interrupted system call, resuming\n"); |
735 continue; | 435 continue; |
736 } | 436 } |
737 | 437 |
738 if (errno == EAGAIN) { | 438 if (errno == EAGAIN) { |
739 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() incomplete header received\n"); | 439 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() incomplete header received\n"); |
740 | 440 |
741 if (!(sess->header_buf = malloc(sess->header_done))) { | 441 if (!(sess->header_buf = malloc(sess->header_done))) { |
742 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() not enough memory\n"); | 442 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() not enough memory\n"); |
743 return NULL; | 443 return NULL; |
744 } | 444 } |
745 | 445 |
746 memcpy(sess->header_buf, &h, sess->header_done); | 446 memcpy(sess->header_buf, &h, sess->header_done); |
747 | 447 |
448 errno = EAGAIN; | |
449 | |
748 return NULL; | 450 return NULL; |
749 } | 451 } |
750 | 452 |
751 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: errno=%d, %s\n", errno, strerror(errno)); | 453 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: errno=%d, %s\n", errno, strerror(errno)); |
752 | 454 |
753 return NULL; | 455 return NULL; |
754 } | 456 } |
755 | 457 |
756 sess->header_done += ret; | 458 sess->header_done += ret; |
759 | 461 |
760 h.type = gg_fix32(h.type); | 462 h.type = gg_fix32(h.type); |
761 h.length = gg_fix32(h.length); | 463 h.length = gg_fix32(h.length); |
762 } else | 464 } else |
763 memcpy(&h, sess->recv_buf, sizeof(h)); | 465 memcpy(&h, sess->recv_buf, sizeof(h)); |
764 | 466 |
765 /* jakie sensowne limity na rozmiar pakietu */ | 467 /* jakie艣 sensowne limity na rozmiar pakietu */ |
766 if (h.length > 65535) { | 468 if (h.length > 65535) { |
767 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() invalid packet length (%d)\n", h.length); | 469 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() invalid packet length (%d)\n", h.length); |
768 errno = ERANGE; | 470 errno = ERANGE; |
769 return NULL; | 471 return NULL; |
770 } | 472 } |
771 | 473 |
772 if (sess->recv_left > 0) { | 474 if (sess->recv_left > 0) { |
773 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() resuming last gg_recv_packet()\n"); | 475 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() resuming last gg_recv_packet()\n"); |
774 size = sess->recv_left; | 476 size = sess->recv_left; |
775 offset = sess->recv_done; | 477 offset = sess->recv_done; |
776 buf = sess->recv_buf; | 478 buf = sess->recv_buf; |
777 } else { | 479 } else { |
778 if (!(buf = malloc(sizeof(h) + h.length + 1))) { | 480 if (!(buf = malloc(sizeof(h) + h.length + 1))) { |
779 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() not enough memory for packet data\n"); | 481 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() not enough memory for packet data\n"); |
780 return NULL; | 482 return NULL; |
781 } | 483 } |
782 | 484 |
783 memcpy(buf, &h, sizeof(h)); | 485 memcpy(buf, &h, sizeof(h)); |
784 | 486 |
786 size = h.length; | 488 size = h.length; |
787 } | 489 } |
788 | 490 |
789 while (size > 0) { | 491 while (size > 0) { |
790 ret = gg_read(sess, buf + sizeof(h) + offset, size); | 492 ret = gg_read(sess, buf + sizeof(h) + offset, size); |
791 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv(%d,%p,%d) = %d\n", sess->fd, buf + sizeof(h) + offset, size, ret); | 493 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() body recv(%d,%p,%d) = %d\n", sess->fd, buf + sizeof(h) + offset, size, ret); |
792 if (!ret) { | 494 if (!ret) { |
793 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed: connection broken\n"); | 495 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed: connection broken\n"); |
794 free(buf); | |
795 errno = ECONNRESET; | 496 errno = ECONNRESET; |
796 return NULL; | 497 return NULL; |
797 } | 498 } |
798 if (ret > -1 && ret <= size) { | 499 if (ret > -1 && ret <= size) { |
799 offset += ret; | 500 offset += ret; |
800 size -= ret; | 501 size -= ret; |
801 } else if (ret == -1) { | 502 } else if (ret == -1) { |
802 int errno2 = errno; | 503 int errno2 = errno; |
803 | 504 |
804 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed (errno=%d, %s)\n", errno, strerror(errno)); | 505 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed (errno=%d, %s)\n", errno, strerror(errno)); |
805 errno = errno2; | 506 errno = errno2; |
806 | 507 |
807 if (errno == EAGAIN) { | 508 if (errno == EAGAIN) { |
808 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() %d bytes received, %d left\n", offset, size); | 509 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() %d bytes received, %d left\n", offset, size); |
809 sess->recv_buf = buf; | 510 sess->recv_buf = buf; |
810 sess->recv_left = size; | 511 sess->recv_left = size; |
811 sess->recv_done = offset; | 512 sess->recv_done = offset; |
812 return NULL; | 513 return NULL; |
813 } | 514 } |
821 sess->recv_left = 0; | 522 sess->recv_left = 0; |
822 | 523 |
823 if ((gg_debug_level & GG_DEBUG_DUMP)) { | 524 if ((gg_debug_level & GG_DEBUG_DUMP)) { |
824 unsigned int i; | 525 unsigned int i; |
825 | 526 |
826 gg_debug(GG_DEBUG_DUMP, "// gg_recv_packet(%.2x)", h.type); | 527 gg_debug_session(sess, GG_DEBUG_DUMP, "// gg_recv_packet(%.2x)", h.type); |
827 for (i = 0; i < sizeof(h) + h.length; i++) | 528 for (i = 0; i < sizeof(h) + h.length; i++) |
828 gg_debug(GG_DEBUG_DUMP, " %.2x", (unsigned char) buf[i]); | 529 gg_debug_session(sess, GG_DEBUG_DUMP, " %.2x", (unsigned char) buf[i]); |
829 gg_debug(GG_DEBUG_DUMP, "\n"); | 530 gg_debug_session(sess, GG_DEBUG_DUMP, "\n"); |
830 } | 531 } |
831 | 532 |
832 return buf; | 533 return buf; |
833 } | 534 } |
834 | 535 |
835 /* | 536 /** |
836 * gg_send_packet() // funkcja wewn阾rzna | 537 * \internal Wysy艂a pakiet do serwera. |
837 * | 538 * |
838 * konstruuje pakiet i wysy砤 go do serwera. | 539 * Funkcja konstruuje pakiet do wys艂ania z dowolnej liczby fragment贸w. Je艣li |
839 * | 540 * rozmiar pakietu jest za du偶y, by m贸c go wys艂a膰 za jednym razem, pozosta艂a |
840 * - sock - deskryptor gniazda | 541 * cz臋艣膰 zostanie zakolejkowana i wys艂ana, gdy b臋dzie to mo偶liwe. |
841 * - type - typ pakietu | 542 * |
842 * - payload_1 - pierwsza cz甓 pakietu | 543 * \param sess Struktura sesji |
843 * - payload_length_1 - d硊go舵 pierwszej cz甓ci | 544 * \param type Rodzaj pakietu |
844 * - payload_2 - druga cz甓 pakietu | 545 * \param ... Lista kolejnych cz臋艣ci pakietu (wska藕nik na bufor i d艂ugo艣膰 |
845 * - payload_length_2 - d硊go舵 drugiej cz甓ci | 546 * typu \c int) zako艅czona \c NULL |
846 * - ... - kolejne cz甓ci pakietu i ich d硊go禼i | 547 * |
847 * - NULL - ko馽owym parametr (konieczny!) | 548 * \return 0 je艣li si臋 powiod艂o, -1 w przypadku b艂臋du |
848 * | |
849 * je秎i si powiod硂, zwraca 0, w przypadku b酬du -1. je秎i errno == ENOMEM, | |
850 * zabrak硂 pami阠i. inaczej by b潮d przy wysy砤niu pakietu. dla errno == 0 | |
851 * nie wys砤no ca砮go pakietu. | |
852 */ | 549 */ |
853 int gg_send_packet(struct gg_session *sess, int type, ...) | 550 int gg_send_packet(struct gg_session *sess, int type, ...) |
854 { | 551 { |
855 struct gg_header *h; | 552 struct gg_header *h; |
856 char *tmp; | 553 char *tmp; |
857 int tmp_length; | 554 unsigned int tmp_length; |
858 void *payload; | 555 void *payload; |
859 unsigned int payload_length; | 556 unsigned int payload_length; |
860 va_list ap; | 557 va_list ap; |
861 int res; | 558 int res; |
862 | 559 |
863 gg_debug(GG_DEBUG_FUNCTION, "** gg_send_packet(%p, 0x%.2x, ...)\n", sess, type); | 560 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_send_packet(%p, 0x%.2x, ...);\n", sess, type); |
864 | 561 |
865 tmp_length = sizeof(struct gg_header); | 562 tmp_length = sizeof(struct gg_header); |
866 | 563 |
867 if (!(tmp = malloc(tmp_length))) { | 564 if (!(tmp = malloc(tmp_length))) { |
868 gg_debug(GG_DEBUG_MISC, "// gg_send_packet() not enough memory for packet header\n"); | 565 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_send_packet() not enough memory for packet header\n"); |
869 return -1; | 566 return -1; |
870 } | 567 } |
871 | 568 |
872 va_start(ap, type); | 569 va_start(ap, type); |
873 | 570 |
877 char *tmp2; | 574 char *tmp2; |
878 | 575 |
879 payload_length = va_arg(ap, unsigned int); | 576 payload_length = va_arg(ap, unsigned int); |
880 | 577 |
881 if (!(tmp2 = realloc(tmp, tmp_length + payload_length))) { | 578 if (!(tmp2 = realloc(tmp, tmp_length + payload_length))) { |
882 gg_debug(GG_DEBUG_MISC, "// gg_send_packet() not enough memory for payload\n"); | 579 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_send_packet() not enough memory for payload\n"); |
883 free(tmp); | 580 free(tmp); |
884 va_end(ap); | 581 va_end(ap); |
885 return -1; | 582 return -1; |
886 } | 583 } |
887 | 584 |
888 tmp = tmp2; | 585 tmp = tmp2; |
889 | 586 |
890 memcpy(tmp + tmp_length, payload, payload_length); | 587 memcpy(tmp + tmp_length, payload, payload_length); |
891 tmp_length += payload_length; | 588 tmp_length += payload_length; |
892 | 589 |
893 payload = va_arg(ap, void *); | 590 payload = va_arg(ap, void *); |
894 } | 591 } |
898 h = (struct gg_header*) tmp; | 595 h = (struct gg_header*) tmp; |
899 h->type = gg_fix32(type); | 596 h->type = gg_fix32(type); |
900 h->length = gg_fix32(tmp_length - sizeof(struct gg_header)); | 597 h->length = gg_fix32(tmp_length - sizeof(struct gg_header)); |
901 | 598 |
902 if ((gg_debug_level & GG_DEBUG_DUMP)) { | 599 if ((gg_debug_level & GG_DEBUG_DUMP)) { |
903 int i; | 600 unsigned int i; |
904 | 601 |
905 gg_debug(GG_DEBUG_DUMP, "// gg_send_packet(0x%.2x)", gg_fix32(h->type)); | 602 gg_debug_session(sess, GG_DEBUG_DUMP, "// gg_send_packet(0x%.2x)", gg_fix32(h->type)); |
906 for (i = 0; i < tmp_length; ++i) | 603 for (i = 0; i < tmp_length; ++i) |
907 gg_debug(GG_DEBUG_DUMP, " %.2x", (unsigned char) tmp[i]); | 604 gg_debug_session(sess, GG_DEBUG_DUMP, " %.2x", (unsigned char) tmp[i]); |
908 gg_debug(GG_DEBUG_DUMP, "\n"); | 605 gg_debug_session(sess, GG_DEBUG_DUMP, "\n"); |
909 } | 606 } |
910 | 607 |
911 if ((res = gg_write(sess, tmp, tmp_length)) < tmp_length) { | 608 res = gg_write(sess, tmp, tmp_length); |
912 gg_debug(GG_DEBUG_MISC, "// gg_send_packet() write() failed. res = %d, errno = %d (%s)\n", res, errno, strerror(errno)); | 609 |
913 free(tmp); | 610 free(tmp); |
914 return -1; | 611 |
915 } | 612 if (res == -1) { |
916 | 613 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_send_packet() write() failed. res = %d, errno = %d (%s)\n", res, errno, strerror(errno)); |
917 free(tmp); | 614 return -1; |
615 } | |
616 | |
617 if (sess->async) | |
618 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_send_packet() partial write(), %d sent, %d left, %d total left\n", res, tmp_length - res, sess->send_left); | |
619 | |
620 if (sess->send_buf) | |
621 sess->check |= GG_CHECK_WRITE; | |
622 | |
918 return 0; | 623 return 0; |
919 } | 624 } |
920 | 625 |
921 /* | 626 /** |
922 * gg_session_callback() // funkcja wewn阾rzna | 627 * \internal Funkcja zwrotna sesji. |
923 * | 628 * |
924 * wywo硑wany z gg_session->callback, wykonuje gg_watch_fd() i pakuje | 629 * Pole \c callback struktury \c gg_session zawiera wska藕nik do tej funkcji. |
925 * do gg_session->event jego wynik. | 630 * Wywo艂uje ona \c gg_watch_fd i zachowuje wynik w polu \c event. |
926 */ | 631 * |
927 static int gg_session_callback(struct gg_session *s) | 632 * \note Korzystanie z tej funkcjonalno艣ci nie jest ju偶 zalecane. |
928 { | 633 * |
929 if (!s) { | 634 * \param sess Struktura sesji |
635 * | |
636 * \return 0 je艣li si臋 powiod艂o, -1 w przypadku b艂臋du | |
637 */ | |
638 static int gg_session_callback(struct gg_session *sess) | |
639 { | |
640 if (!sess) { | |
930 errno = EFAULT; | 641 errno = EFAULT; |
931 return -1; | 642 return -1; |
932 } | 643 } |
933 | 644 |
934 return ((s->event = gg_watch_fd(s)) != NULL) ? 0 : -1; | 645 return ((sess->event = gg_watch_fd(sess)) != NULL) ? 0 : -1; |
935 } | 646 } |
936 | 647 |
937 /* | 648 /** |
938 * gg_login() | 649 * 艁膮czy si臋 z serwerem Gadu-Gadu. |
939 * | 650 * |
940 * rozpoczyna procedur 潮czenia si z serwerem. reszt obs硊guje si przez | 651 * Przy po艂膮czeniu synchronicznym funkcja zako艅czy dzia艂anie po nawi膮zaniu |
941 * gg_watch_fd(). | 652 * po艂膮czenia lub gdy wyst膮pi b艂膮d. Po udanym po艂膮czeniu nale偶y wywo艂ywa膰 |
942 * | 653 * funkcj臋 \c gg_watch_fd(), kt贸ra odbiera informacje od serwera i zwraca |
943 * UWAGA! program musi obs硊縴 SIGCHLD, je秎i 潮czy si asynchronicznie, | 654 * informacje o zdarzeniach. |
944 * 縠by poprawnie zamkn辨 proces resolvera. | 655 * |
945 * | 656 * Przy po艂膮czeniu asynchronicznym funkcja rozpocznie procedur臋 po艂膮czenia |
946 * - p - struktura opisuj眂a pocz眛kowy stan. wymagane pola: uin, | 657 * i zwr贸ci zaalokowan膮 struktur臋. Pole \c fd struktury \c gg_session zawiera |
947 * password | 658 * deskryptor, kt贸ry nale偶y obserwowa膰 funkcj膮 \c select, \c poll lub za |
948 * | 659 * pomoc膮 mechanizm贸w u偶ytej p臋tli zdarze艅 (Glib, Qt itp.). Pole \c check |
949 * w przypadku b酬du NULL, je秎i idzie dobrze (async) albo posz硂 | 660 * jest mask膮 bitow膮 m贸wi膮c膮, czy biblioteka chce by膰 informowana o mo偶liwo艣ci |
950 * dobrze (sync), zwr骳i wska糿ik do zaalokowanej struct gg_session. | 661 * odczytu danych (\c GG_CHECK_READ) czy zapisu danych (\c GG_CHECK_WRITE). |
662 * Po zaobserwowaniu zmian na deskryptorze nale偶y wywo艂a膰 funkcj臋 | |
663 * \c gg_watch_fd(). Podczas korzystania z po艂膮cze艅 asynchronicznych, w trakcie | |
664 * po艂膮czenia mo偶e zosta膰 stworzony dodatkowy proces rozwi膮zuj膮cy nazw臋 | |
665 * serwera -- z tego powodu program musi poprawnie obs艂u偶y膰 sygna艂 SIGCHLD. | |
666 * | |
667 * \note Po nawi膮zaniu po艂膮czenia z serwerem nale偶y wys艂a膰 list臋 kontakt贸w | |
668 * za pomoc膮 funkcji \c gg_notify() lub \c gg_notify_ex(). | |
669 * | |
670 * \param p Struktura opisuj膮ca parametry po艂膮czenia. Wymagane pola: uin, | |
671 * password, async. | |
672 * | |
673 * \return Wska藕nik do zaalokowanej struktury sesji \c gg_session lub NULL | |
674 * w przypadku b艂臋du. | |
675 * | |
676 * \ingroup login | |
951 */ | 677 */ |
952 struct gg_session *gg_login(const struct gg_login_params *p) | 678 struct gg_session *gg_login(const struct gg_login_params *p) |
953 { | 679 { |
954 struct gg_session *sess = NULL; | 680 struct gg_session *sess = NULL; |
955 char *hostname; | 681 char *hostname; |
979 if (!(sess->password = strdup(p->password))) { | 705 if (!(sess->password = strdup(p->password))) { |
980 gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for password\n"); | 706 gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for password\n"); |
981 goto fail; | 707 goto fail; |
982 } | 708 } |
983 | 709 |
984 if (p->status_descr && !(sess->initial_descr = strdup(p->status_descr))) { | 710 if (p->hash_type < 0 || p->hash_type > GG_LOGIN_HASH_SHA1) { |
985 gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for status\n"); | 711 gg_debug(GG_DEBUG_MISC, "// gg_login() invalid arguments. unknown hash type (%d)\n", p->hash_type); |
712 errno = EFAULT; | |
986 goto fail; | 713 goto fail; |
987 } | 714 } |
988 | 715 |
989 sess->uin = p->uin; | 716 sess->uin = p->uin; |
990 sess->state = GG_STATE_RESOLVING; | 717 sess->state = GG_STATE_RESOLVING; |
997 sess->destroy = gg_free_session; | 724 sess->destroy = gg_free_session; |
998 sess->port = (p->server_port) ? p->server_port : ((gg_proxy_enabled) ? GG_HTTPS_PORT : GG_DEFAULT_PORT); | 725 sess->port = (p->server_port) ? p->server_port : ((gg_proxy_enabled) ? GG_HTTPS_PORT : GG_DEFAULT_PORT); |
999 sess->server_addr = p->server_addr; | 726 sess->server_addr = p->server_addr; |
1000 sess->external_port = p->external_port; | 727 sess->external_port = p->external_port; |
1001 sess->external_addr = p->external_addr; | 728 sess->external_addr = p->external_addr; |
729 | |
730 sess->protocol_features = (p->protocol_features & ~(GG_FEATURE_STATUS77 | GG_FEATURE_MSG77)); | |
731 | |
732 if (!(p->protocol_features & GG_FEATURE_STATUS77)) | |
733 sess->protocol_features |= GG_FEATURE_STATUS80; | |
734 | |
735 if (!(p->protocol_features & GG_FEATURE_MSG77)) | |
736 sess->protocol_features |= GG_FEATURE_MSG80; | |
737 | |
1002 sess->protocol_version = (p->protocol_version) ? p->protocol_version : GG_DEFAULT_PROTOCOL_VERSION; | 738 sess->protocol_version = (p->protocol_version) ? p->protocol_version : GG_DEFAULT_PROTOCOL_VERSION; |
739 | |
1003 if (p->era_omnix) | 740 if (p->era_omnix) |
1004 sess->protocol_version |= GG_ERA_OMNIX_MASK; | 741 sess->protocol_flags |= GG_ERA_OMNIX_MASK; |
1005 if (p->has_audio) | 742 if (p->has_audio) |
1006 sess->protocol_version |= GG_HAS_AUDIO_MASK; | 743 sess->protocol_flags |= GG_HAS_AUDIO_MASK; |
1007 sess->client_version = (p->client_version) ? strdup(p->client_version) : NULL; | 744 sess->client_version = (p->client_version) ? strdup(p->client_version) : NULL; |
1008 sess->last_sysmsg = p->last_sysmsg; | 745 sess->last_sysmsg = p->last_sysmsg; |
1009 sess->image_size = p->image_size; | 746 sess->image_size = p->image_size; |
1010 sess->pid = -1; | 747 sess->pid = -1; |
748 sess->encoding = p->encoding; | |
749 | |
750 if (gg_session_set_resolver(sess, p->resolver) == -1) { | |
751 gg_debug(GG_DEBUG_MISC, "// gg_login() invalid arguments. unsupported resolver type (%d)\n", p->resolver); | |
752 errno = EFAULT; | |
753 goto fail; | |
754 } | |
755 | |
756 if (p->status_descr) { | |
757 int max_length; | |
758 | |
759 if (sess->protocol_version >= 0x2d) | |
760 max_length = GG_STATUS_DESCR_MAXSIZE; | |
761 else | |
762 max_length = GG_STATUS_DESCR_MAXSIZE_PRE_8_0; | |
763 | |
764 if (sess->protocol_version >= 0x2d && p->encoding != GG_ENCODING_UTF8) | |
765 sess->initial_descr = gg_cp_to_utf8(p->status_descr); | |
766 else | |
767 sess->initial_descr = strdup(p->status_descr); | |
768 | |
769 if (!sess->initial_descr) { | |
770 gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for status\n"); | |
771 goto fail; | |
772 } | |
773 | |
774 // XXX pami臋ta膰, 偶eby nie ci膮膰 w 艣rodku znaku utf-8 | |
775 | |
776 if (strlen(sess->initial_descr) > max_length) | |
777 sess->initial_descr[max_length] = 0; | |
778 } | |
1011 | 779 |
1012 if (p->tls == 1) { | 780 if (p->tls == 1) { |
1013 #ifdef __GG_LIBGADU_HAVE_OPENSSL | 781 #ifdef GG_CONFIG_HAVE_OPENSSL |
1014 char buf[1024]; | 782 char buf[1024]; |
1015 | 783 |
1016 OpenSSL_add_ssl_algorithms(); | 784 OpenSSL_add_ssl_algorithms(); |
1017 | 785 |
1018 if (!RAND_status()) { | 786 if (!RAND_status()) { |
1021 time_t time; | 789 time_t time; |
1022 void *ptr; | 790 void *ptr; |
1023 } rstruct; | 791 } rstruct; |
1024 | 792 |
1025 time(&rstruct.time); | 793 time(&rstruct.time); |
1026 rstruct.ptr = (void *) &rstruct; | 794 rstruct.ptr = (void *) &rstruct; |
1027 | 795 |
1028 RAND_seed((void *) rdata, sizeof(rdata)); | 796 RAND_seed((void *) rdata, sizeof(rdata)); |
1029 RAND_seed((void *) &rstruct, sizeof(rstruct)); | 797 RAND_seed((void *) &rstruct, sizeof(rstruct)); |
1030 } | 798 } |
1031 | 799 |
1048 } | 816 } |
1049 #else | 817 #else |
1050 gg_debug(GG_DEBUG_MISC, "// gg_login() client requested TLS but no support compiled in\n"); | 818 gg_debug(GG_DEBUG_MISC, "// gg_login() client requested TLS but no support compiled in\n"); |
1051 #endif | 819 #endif |
1052 } | 820 } |
1053 | 821 |
1054 if (gg_proxy_enabled) { | 822 if (gg_proxy_enabled) { |
1055 hostname = gg_proxy_host; | 823 hostname = gg_proxy_host; |
1056 sess->proxy_port = port = gg_proxy_port; | 824 sess->proxy_port = port = gg_proxy_port; |
1057 } else { | 825 } else { |
1058 hostname = GG_APPMSG_HOST; | 826 hostname = GG_APPMSG_HOST; |
1059 port = GG_APPMSG_PORT; | 827 port = GG_APPMSG_PORT; |
1060 } | 828 } |
1061 | 829 |
830 if (p->hash_type) | |
831 sess->hash_type = p->hash_type; | |
832 else | |
833 sess->hash_type = GG_LOGIN_HASH_SHA1; | |
834 | |
1062 if (!p->async) { | 835 if (!p->async) { |
1063 struct in_addr a; | 836 struct in_addr addr; |
1064 | 837 |
1065 if (!p->server_addr || !p->server_port) { | 838 if (!sess->server_addr) { |
1066 if ((a.s_addr = inet_addr(hostname)) == INADDR_NONE) { | 839 if ((addr.s_addr = inet_addr(hostname)) == INADDR_NONE) { |
1067 struct in_addr *hn; | 840 if (gg_gethostbyname_real(hostname, &addr, 0) == -1) { |
1068 | |
1069 if (!(hn = gg_gethostbyname(hostname))) { | |
1070 gg_debug(GG_DEBUG_MISC, "// gg_login() host \"%s\" not found\n", hostname); | 841 gg_debug(GG_DEBUG_MISC, "// gg_login() host \"%s\" not found\n", hostname); |
1071 goto fail; | 842 goto fail; |
1072 } else { | |
1073 a.s_addr = hn->s_addr; | |
1074 free(hn); | |
1075 } | 843 } |
1076 } | 844 } |
1077 } else { | 845 } else { |
1078 a.s_addr = p->server_addr; | 846 addr.s_addr = sess->server_addr; |
1079 port = p->server_port; | 847 port = sess->port; |
1080 } | 848 } |
1081 | 849 |
1082 sess->hub_addr = a.s_addr; | 850 sess->hub_addr = addr.s_addr; |
1083 | 851 |
1084 if (gg_proxy_enabled) | 852 if (gg_proxy_enabled) |
1085 sess->proxy_addr = a.s_addr; | 853 sess->proxy_addr = addr.s_addr; |
1086 | 854 |
1087 if ((sess->fd = gg_connect(&a, port, 0)) == -1) { | 855 if ((sess->fd = gg_connect(&addr, port, 0)) == -1) { |
1088 gg_debug(GG_DEBUG_MISC, "// gg_login() connection failed (errno=%d, %s)\n", errno, strerror(errno)); | 856 gg_debug(GG_DEBUG_MISC, "// gg_login() connection failed (errno=%d, %s)\n", errno, strerror(errno)); |
1089 goto fail; | 857 |
1090 } | 858 /* nie wysz艂o? pr贸bujemy portu 443. */ |
1091 | 859 if (sess->server_addr) { |
1092 if (p->server_addr && p->server_port) | 860 sess->port = GG_HTTPS_PORT; |
861 | |
862 if ((sess->fd = gg_connect(&addr, GG_HTTPS_PORT, 0)) == -1) { | |
863 /* ostatnia deska ratunku zawiod艂a? | |
864 * w takim razie zwijamy manatki. */ | |
865 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_login() connection failed (errno=%d, %s)\n", errno, strerror(errno)); | |
866 goto fail; | |
867 } | |
868 } else { | |
869 goto fail; | |
870 } | |
871 } | |
872 | |
873 if (sess->server_addr) | |
1093 sess->state = GG_STATE_CONNECTING_GG; | 874 sess->state = GG_STATE_CONNECTING_GG; |
1094 else | 875 else |
1095 sess->state = GG_STATE_CONNECTING_HUB; | 876 sess->state = GG_STATE_CONNECTING_HUB; |
1096 | 877 |
1097 while (sess->state != GG_STATE_CONNECTED) { | 878 while (sess->state != GG_STATE_CONNECTED) { |
1112 gg_event_free(e); | 893 gg_event_free(e); |
1113 } | 894 } |
1114 | 895 |
1115 return sess; | 896 return sess; |
1116 } | 897 } |
1117 | 898 |
1118 if (!sess->server_addr || gg_proxy_enabled) { | 899 if (!sess->server_addr || gg_proxy_enabled) { |
1119 #ifdef __GG_LIBGADU_HAVE_PTHREAD | 900 if (sess->resolver_start(&sess->fd, &sess->resolver, hostname) == -1) { |
1120 if (gg_resolve_pthread(&sess->fd, &sess->resolver, hostname)) { | |
1121 #elif defined _WIN32 | |
1122 if (gg_resolve_win32thread(&sess->fd, &sess->resolver, hostname)) { | |
1123 #else | |
1124 if (gg_resolve(&sess->fd, &sess->pid, hostname)) { | |
1125 #endif | |
1126 gg_debug(GG_DEBUG_MISC, "// gg_login() resolving failed (errno=%d, %s)\n", errno, strerror(errno)); | 901 gg_debug(GG_DEBUG_MISC, "// gg_login() resolving failed (errno=%d, %s)\n", errno, strerror(errno)); |
1127 goto fail; | 902 goto fail; |
1128 } | 903 } |
1129 } else { | 904 } else { |
1130 if ((sess->fd = gg_connect(&sess->server_addr, sess->port, sess->async)) == -1) { | 905 if ((sess->fd = gg_connect(&sess->server_addr, sess->port, sess->async)) == -1) { |
1131 gg_debug(GG_DEBUG_MISC, "// gg_login() direct connection failed (errno=%d, %s)\n", errno, strerror(errno)); | 906 gg_debug(GG_DEBUG_MISC, "// gg_login() direct connection failed (errno=%d, %s)\n", errno, strerror(errno)); |
1132 goto fail; | 907 goto fail; |
1133 } | 908 } |
1134 sess->state = GG_STATE_CONNECTING_GG; | 909 sess->state = GG_STATE_CONNECTING_GG; |
1135 sess->check = GG_CHECK_WRITE; | 910 sess->check = GG_CHECK_WRITE; |
911 sess->soft_timeout = 1; | |
1136 } | 912 } |
1137 | 913 |
1138 return sess; | 914 return sess; |
1139 | 915 |
1140 fail: | 916 fail: |
1141 if (sess) { | 917 if (sess) { |
1142 if (sess->password) | 918 free(sess->password); |
1143 free(sess->password); | 919 free(sess->initial_descr); |
1144 if (sess->initial_descr) | |
1145 free(sess->initial_descr); | |
1146 free(sess); | 920 free(sess); |
1147 } | 921 } |
1148 | 922 |
1149 return NULL; | 923 return NULL; |
1150 } | 924 } |
1151 | 925 |
1152 /* | 926 /** |
1153 * gg_free_session() | 927 * Wysy艂a do serwera pakiet utrzymania po艂膮czenia. |
1154 * | 928 * |
1155 * pr骲uje zamkn辨 po潮czenia i zwalnia pami赕 zajmowan przez sesj. | 929 * Klient powinien regularnie co minut臋 wysy艂a膰 pakiet utrzymania po艂膮czenia, |
1156 * | 930 * inaczej serwer uzna, 偶e klient straci艂 艂膮czno艣膰 z sieci膮 i zerwie |
1157 * - sess - opis sesji | 931 * po艂膮czenie. |
1158 */ | 932 * |
1159 void gg_free_session(struct gg_session *sess) | 933 * \param sess Struktura sesji |
934 * | |
935 * \return 0 je艣li si臋 powiod艂o, -1 w przypadku b艂臋du | |
936 * | |
937 * \ingroup login | |
938 */ | |
939 int gg_ping(struct gg_session *sess) | |
940 { | |
941 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_ping(%p);\n", sess); | |
942 | |
943 if (!sess) { | |
944 errno = EFAULT; | |
945 return -1; | |
946 } | |
947 | |
948 if (sess->state != GG_STATE_CONNECTED) { | |
949 errno = ENOTCONN; | |
950 return -1; | |
951 } | |
952 | |
953 return gg_send_packet(sess, GG_PING, NULL); | |
954 } | |
955 | |
956 /** | |
957 * Ko艅czy po艂膮czenie z serwerem. | |
958 * | |
959 * Funkcja nie zwalnia zasob贸w, wi臋c po jej wywo艂aniu nale偶y u偶y膰 | |
960 * \c gg_free_session(). Je艣li chce si臋 ustawi膰 opis niedost臋pno艣ci, nale偶y | |
961 * wcze艣niej wywo艂a膰 funkcj臋 \c gg_change_status_descr() lub | |
962 * \c gg_change_status_descr_time(). | |
963 * | |
964 * \note Je艣li w buforze nadawczym po艂膮czenia z serwerem znajduj膮 si臋 jeszcze | |
965 * dane (np. z powodu strat pakiet贸w na 艂膮czu), prawdopodobnie zostan膮 one | |
966 * utracone przy zrywaniu po艂膮czenia. | |
967 * | |
968 * \param sess Struktura sesji | |
969 * | |
970 * \ingroup login | |
971 */ | |
972 void gg_logoff(struct gg_session *sess) | |
1160 { | 973 { |
1161 if (!sess) | 974 if (!sess) |
1162 return; | 975 return; |
1163 | 976 |
1164 /* XXX dopisa zwalnianie i zamykanie wszystkiego, co mog硂 zosta */ | 977 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_logoff(%p);\n", sess); |
1165 | 978 |
1166 if (sess->password) | 979 if (GG_S_NA(sess->status)) |
1167 free(sess->password); | |
1168 | |
1169 if (sess->initial_descr) | |
1170 free(sess->initial_descr); | |
1171 | |
1172 if (sess->client_version) | |
1173 free(sess->client_version); | |
1174 | |
1175 if (sess->header_buf) | |
1176 free(sess->header_buf); | |
1177 | |
1178 #ifdef __GG_LIBGADU_HAVE_OPENSSL | |
1179 if (sess->ssl) | |
1180 SSL_free(sess->ssl); | |
1181 | |
1182 if (sess->ssl_ctx) | |
1183 SSL_CTX_free(sess->ssl_ctx); | |
1184 #endif | |
1185 | |
1186 #ifdef __GG_LIBGADU_HAVE_PTHREAD | |
1187 if (sess->resolver) { | |
1188 pthread_cancel(*((pthread_t*) sess->resolver)); | |
1189 free(sess->resolver); | |
1190 sess->resolver = NULL; | |
1191 } | |
1192 #elif defined _WIN32 | |
1193 if (sess->resolver) { | |
1194 HANDLE h = sess->resolver; | |
1195 TerminateThread(h, 0); | |
1196 CloseHandle(h); | |
1197 sess->resolver = NULL; | |
1198 } | |
1199 #else | |
1200 if (sess->pid != -1) | |
1201 waitpid(sess->pid, NULL, WNOHANG); | |
1202 #endif | |
1203 | |
1204 if (sess->fd != -1) | |
1205 close(sess->fd); | |
1206 | |
1207 while (sess->images) | |
1208 gg_image_queue_remove(sess, sess->images, 1); | |
1209 | |
1210 free(sess); | |
1211 } | |
1212 | |
1213 /* | |
1214 * gg_change_status() | |
1215 * | |
1216 * zmienia status u縴tkownika. przydatne do /away i /busy oraz /quit. | |
1217 * | |
1218 * - sess - opis sesji | |
1219 * - status - nowy status u縴tkownika | |
1220 * | |
1221 * 0, -1. | |
1222 */ | |
1223 int gg_change_status(struct gg_session *sess, int status) | |
1224 { | |
1225 struct gg_new_status p; | |
1226 | |
1227 gg_debug(GG_DEBUG_FUNCTION, "** gg_change_status(%p, %d);\n", sess, status); | |
1228 | |
1229 if (!sess) { | |
1230 errno = EFAULT; | |
1231 return -1; | |
1232 } | |
1233 | |
1234 if (sess->state != GG_STATE_CONNECTED) { | |
1235 errno = ENOTCONN; | |
1236 return -1; | |
1237 } | |
1238 | |
1239 p.status = gg_fix32(status); | |
1240 | |
1241 sess->status = status; | |
1242 | |
1243 return gg_send_packet(sess, GG_NEW_STATUS, &p, sizeof(p), NULL); | |
1244 } | |
1245 | |
1246 /* | |
1247 * gg_change_status_descr() | |
1248 * | |
1249 * zmienia status u縴tkownika na opisowy. | |
1250 * | |
1251 * - sess - opis sesji | |
1252 * - status - nowy status u縴tkownika | |
1253 * - descr - opis statusu | |
1254 * | |
1255 * 0, -1. | |
1256 */ | |
1257 int gg_change_status_descr(struct gg_session *sess, int status, const char *descr) | |
1258 { | |
1259 struct gg_new_status p; | |
1260 | |
1261 gg_debug(GG_DEBUG_FUNCTION, "** gg_change_status_descr(%p, %d, \"%s\");\n", sess, status, descr); | |
1262 | |
1263 if (!sess || !descr) { | |
1264 errno = EFAULT; | |
1265 return -1; | |
1266 } | |
1267 | |
1268 if (sess->state != GG_STATE_CONNECTED) { | |
1269 errno = ENOTCONN; | |
1270 return -1; | |
1271 } | |
1272 | |
1273 p.status = gg_fix32(status); | |
1274 | |
1275 sess->status = status; | |
1276 | |
1277 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); | |
1278 } | |
1279 | |
1280 /* | |
1281 * gg_change_status_descr_time() | |
1282 * | |
1283 * zmienia status u縴tkownika na opisowy z godzin powrotu. | |
1284 * | |
1285 * - sess - opis sesji | |
1286 * - status - nowy status u縴tkownika | |
1287 * - descr - opis statusu | |
1288 * - time - czas w formacie uniksowym | |
1289 * | |
1290 * 0, -1. | |
1291 */ | |
1292 int gg_change_status_descr_time(struct gg_session *sess, int status, const char *descr, int time) | |
1293 { | |
1294 struct gg_new_status p; | |
1295 uint32_t newtime; | |
1296 | |
1297 gg_debug(GG_DEBUG_FUNCTION, "** gg_change_status_descr_time(%p, %d, \"%s\", %d);\n", sess, status, descr, time); | |
1298 | |
1299 if (!sess || !descr || !time) { | |
1300 errno = EFAULT; | |
1301 return -1; | |
1302 } | |
1303 | |
1304 if (sess->state != GG_STATE_CONNECTED) { | |
1305 errno = ENOTCONN; | |
1306 return -1; | |
1307 } | |
1308 | |
1309 p.status = gg_fix32(status); | |
1310 | |
1311 sess->status = status; | |
1312 | |
1313 newtime = gg_fix32(time); | |
1314 | |
1315 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); | |
1316 } | |
1317 | |
1318 /* | |
1319 * gg_logoff() | |
1320 * | |
1321 * wylogowuje u縴tkownika i zamyka po潮czenie, ale nie zwalnia pami阠i. | |
1322 * | |
1323 * - sess - opis sesji | |
1324 */ | |
1325 void gg_logoff(struct gg_session *sess) | |
1326 { | |
1327 if (!sess) | |
1328 return; | |
1329 | |
1330 gg_debug(GG_DEBUG_FUNCTION, "** gg_logoff(%p);\n", sess); | |
1331 | |
1332 if (GG_S_NA(sess->status & ~GG_STATUS_FRIENDS_MASK)) | |
1333 gg_change_status(sess, GG_STATUS_NOT_AVAIL); | 980 gg_change_status(sess, GG_STATUS_NOT_AVAIL); |
1334 | 981 |
1335 #ifdef __GG_LIBGADU_HAVE_OPENSSL | 982 #ifdef GG_CONFIG_HAVE_OPENSSL |
1336 if (sess->ssl) | 983 if (sess->ssl) |
1337 SSL_shutdown(sess->ssl); | 984 SSL_shutdown(sess->ssl); |
1338 #endif | 985 #endif |
1339 | 986 |
1340 #ifdef __GG_LIBGADU_HAVE_PTHREAD | 987 sess->resolver_cleanup(&sess->resolver, 1); |
1341 if (sess->resolver) { | 988 |
1342 pthread_cancel(*((pthread_t*) sess->resolver)); | |
1343 free(sess->resolver); | |
1344 sess->resolver = NULL; | |
1345 } | |
1346 #elif defined _WIN32 | |
1347 if (sess->resolver) { | |
1348 HANDLE h = sess->resolver; | |
1349 TerminateThread(h, 0); | |
1350 CloseHandle(h); | |
1351 sess->resolver = NULL; | |
1352 } | |
1353 #else | |
1354 if (sess->pid != -1) { | |
1355 waitpid(sess->pid, NULL, WNOHANG); | |
1356 sess->pid = -1; | |
1357 } | |
1358 #endif | |
1359 | |
1360 if (sess->fd != -1) { | 989 if (sess->fd != -1) { |
1361 shutdown(sess->fd, SHUT_RDWR); | 990 shutdown(sess->fd, SHUT_RDWR); |
1362 close(sess->fd); | 991 close(sess->fd); |
1363 sess->fd = -1; | 992 sess->fd = -1; |
1364 } | 993 } |
1365 } | 994 |
1366 | 995 if (sess->send_buf) { |
1367 /* | 996 free(sess->send_buf); |
1368 * gg_image_request() | 997 sess->send_buf = NULL; |
1369 * | 998 sess->send_left = 0; |
1370 * wysy砤 勘danie wys砤nia obrazka o podanych parametrach. | 999 } |
1371 * | 1000 } |
1372 * - sess - opis sesji | 1001 |
1373 * - recipient - numer adresata | 1002 /** |
1374 * - size - rozmiar obrazka | 1003 * Zwalnia zasoby u偶ywane przez po艂膮czenie z serwerem. Funkcj臋 nale偶y wywo艂a膰 |
1375 * - crc32 - suma kontrolna obrazka | 1004 * po zamkni臋ciu po艂膮czenia z serwerem, by nie doprowadzi膰 do wycieku zasob贸w |
1376 * | 1005 * systemowych. |
1377 * 0/-1 | 1006 * |
1007 * \param sess Struktura sesji | |
1008 * | |
1009 * \ingroup login | |
1010 */ | |
1011 void gg_free_session(struct gg_session *sess) | |
1012 { | |
1013 struct gg_dcc7 *dcc; | |
1014 | |
1015 if (!sess) | |
1016 return; | |
1017 | |
1018 /* XXX dopisa膰 zwalnianie i zamykanie wszystkiego, co mog艂o zosta膰 */ | |
1019 | |
1020 free(sess->password); | |
1021 free(sess->initial_descr); | |
1022 free(sess->client_version); | |
1023 free(sess->header_buf); | |
1024 | |
1025 #ifdef GG_CONFIG_HAVE_OPENSSL | |
1026 if (sess->ssl) | |
1027 SSL_free(sess->ssl); | |
1028 | |
1029 if (sess->ssl_ctx) | |
1030 SSL_CTX_free(sess->ssl_ctx); | |
1031 #endif | |
1032 | |
1033 sess->resolver_cleanup(&sess->resolver, 1); | |
1034 | |
1035 if (sess->fd != -1) | |
1036 close(sess->fd); | |
1037 | |
1038 while (sess->images) | |
1039 gg_image_queue_remove(sess, sess->images, 1); | |
1040 | |
1041 free(sess->send_buf); | |
1042 | |
1043 for (dcc = sess->dcc7_list; dcc; dcc = dcc->next) | |
1044 dcc->sess = NULL; | |
1045 | |
1046 free(sess); | |
1047 } | |
1048 | |
1049 #ifndef DOXYGEN | |
1050 | |
1051 /** | |
1052 * \internal Funkcja wysy艂aj膮ca pakiet zmiany statusu u偶ytkownika. | |
1053 * | |
1054 * \param sess Struktura sesji | |
1055 * \param status Nowy status u偶ytkownika | |
1056 * \param descr Opis statusu u偶ytkownika (lub \c NULL) | |
1057 * \param time Czas powrotu w postaci uniksowego znacznika czasu (lub 0) | |
1058 * | |
1059 * \return 0 je艣li si臋 powiod艂o, -1 w przypadku b艂臋du | |
1060 * | |
1061 * \ingroup status | |
1062 */ | |
1063 static int gg_change_status_common(struct gg_session *sess, int status, const char *descr, int time) | |
1064 { | |
1065 char *new_descr = NULL; | |
1066 uint32_t new_time; | |
1067 int descr_len = 0; | |
1068 int descr_len_max; | |
1069 int packet_type; | |
1070 int append_null = 0; | |
1071 int res; | |
1072 | |
1073 if (!sess) { | |
1074 errno = EFAULT; | |
1075 return -1; | |
1076 } | |
1077 | |
1078 if (sess->state != GG_STATE_CONNECTED) { | |
1079 errno = ENOTCONN; | |
1080 return -1; | |
1081 } | |
1082 | |
1083 /* XXX, obcina膰 stany kt贸rych stary protok贸艂 niezna (czyt. dnd->aw; ffc->av) */ | |
1084 | |
1085 /* dodaj flag臋 obs艂ugi po艂膮cze艅 g艂osowych zgodn膮 z GG 7.x */ | |
1086 if ((sess->protocol_version >= 0x2a) && (sess->protocol_version < 0x2d /* ? */ ) && (sess->protocol_flags & GG_HAS_AUDIO_MASK) && !GG_S_I(status)) | |
1087 status |= GG_STATUS_VOICE_MASK; | |
1088 | |
1089 sess->status = status; | |
1090 | |
1091 if (sess->protocol_version >= 0x2d) { | |
1092 if (descr != NULL && sess->encoding != GG_ENCODING_UTF8) { | |
1093 new_descr = gg_cp_to_utf8(descr); | |
1094 | |
1095 if (!new_descr) | |
1096 return -1; | |
1097 } | |
1098 | |
1099 if (sess->protocol_version >= 0x2e) | |
1100 packet_type = GG_NEW_STATUS80; | |
1101 else /* sess->protocol_version == 0x2d */ | |
1102 packet_type = GG_NEW_STATUS80BETA; | |
1103 descr_len_max = GG_STATUS_DESCR_MAXSIZE; | |
1104 append_null = 1; | |
1105 | |
1106 } else { | |
1107 packet_type = GG_NEW_STATUS; | |
1108 descr_len_max = GG_STATUS_DESCR_MAXSIZE_PRE_8_0; | |
1109 | |
1110 if (time != 0) | |
1111 append_null = 1; | |
1112 } | |
1113 | |
1114 if (descr) { | |
1115 descr_len = strlen((new_descr) ? new_descr : descr); | |
1116 | |
1117 if (descr_len > descr_len_max) | |
1118 descr_len = descr_len_max; | |
1119 | |
1120 // XXX pami臋ta膰 o tym, 偶eby nie ucina膰 w 艣rodku znaku utf-8 | |
1121 } | |
1122 | |
1123 if (time) | |
1124 new_time = gg_fix32(time); | |
1125 | |
1126 if (packet_type == GG_NEW_STATUS80) { | |
1127 struct gg_new_status80 p; | |
1128 | |
1129 p.status = gg_fix32(status); | |
1130 p.flags = gg_fix32(0x00800001); | |
1131 p.description_size = gg_fix32(descr_len); | |
1132 res = gg_send_packet(sess, | |
1133 packet_type, | |
1134 &p, | |
1135 sizeof(p), | |
1136 (new_descr) ? new_descr : descr, | |
1137 descr_len, | |
1138 NULL); | |
1139 | |
1140 } else { | |
1141 struct gg_new_status p; | |
1142 | |
1143 p.status = gg_fix32(status); | |
1144 res = gg_send_packet(sess, | |
1145 packet_type, | |
1146 &p, | |
1147 sizeof(p), | |
1148 (new_descr) ? new_descr : descr, | |
1149 descr_len, | |
1150 (append_null) ? "\0" : NULL, | |
1151 (append_null) ? 1 : 0, | |
1152 (time) ? &new_time : NULL, | |
1153 (time) ? sizeof(new_time) : 0, | |
1154 NULL); | |
1155 } | |
1156 | |
1157 free(new_descr); | |
1158 return res; | |
1159 } | |
1160 | |
1161 #endif /* DOXYGEN */ | |
1162 | |
1163 /** | |
1164 * Zmienia status u偶ytkownika. | |
1165 * | |
1166 * \param sess Struktura sesji | |
1167 * \param status Nowy status u偶ytkownika | |
1168 * | |
1169 * \return 0 je艣li si臋 powiod艂o, -1 w przypadku b艂臋du | |
1170 * | |
1171 * \ingroup status | |
1172 */ | |
1173 int gg_change_status(struct gg_session *sess, int status) | |
1174 { | |
1175 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_change_status(%p, %d);\n", sess, status); | |
1176 | |
1177 return gg_change_status_common(sess, status, NULL, 0); | |
1178 } | |
1179 | |
1180 /** | |
1181 * Zmienia status u偶ytkownika na status opisowy. | |
1182 * | |
1183 * \param sess Struktura sesji | |
1184 * \param status Nowy status u偶ytkownika | |
1185 * \param descr Opis statusu u偶ytkownika | |
1186 * | |
1187 * \return 0 je艣li si臋 powiod艂o, -1 w przypadku b艂臋du | |
1188 * | |
1189 * \ingroup status | |
1190 */ | |
1191 int gg_change_status_descr(struct gg_session *sess, int status, const char *descr) | |
1192 { | |
1193 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_change_status_descr(%p, %d, \"%s\");\n", sess, status, descr); | |
1194 | |
1195 return gg_change_status_common(sess, status, descr, 0); | |
1196 } | |
1197 | |
1198 /** | |
1199 * Zmienia status u偶ytkownika na status opisowy z podanym czasem powrotu. | |
1200 * | |
1201 * \param sess Struktura sesji | |
1202 * \param status Nowy status u偶ytkownika | |
1203 * \param descr Opis statusu u偶ytkownika | |
1204 * \param time Czas powrotu w postaci uniksowego znacznika czasu | |
1205 * | |
1206 * \return 0 je艣li si臋 powiod艂o, -1 w przypadku b艂臋du | |
1207 * | |
1208 * \ingroup status | |
1209 */ | |
1210 int gg_change_status_descr_time(struct gg_session *sess, int status, const char *descr, int time) | |
1211 { | |
1212 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_change_status_descr_time(%p, %d, \"%s\", %d);\n", sess, status, descr, time); | |
1213 | |
1214 return gg_change_status_common(sess, status, descr, time); | |
1215 } | |
1216 | |
1217 /** | |
1218 * Wysy艂a wiadomo艣膰 do u偶ytkownika. | |
1219 * | |
1220 * Zwraca losowy numer sekwencyjny, kt贸ry mo偶na zignorowa膰 albo wykorzysta膰 | |
1221 * do potwierdzenia. | |
1222 * | |
1223 * \param sess Struktura sesji | |
1224 * \param msgclass Klasa wiadomo艣ci | |
1225 * \param recipient Numer adresata | |
1226 * \param message Tre艣膰 wiadomo艣ci | |
1227 * | |
1228 * \return Numer sekwencyjny wiadomo艣ci lub -1 w przypadku b艂臋du. | |
1229 * | |
1230 * \ingroup messages | |
1231 */ | |
1232 int gg_send_message(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message) | |
1233 { | |
1234 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_send_message(%p, %d, %u, %p)\n", sess, msgclass, recipient, message); | |
1235 | |
1236 return gg_send_message_confer_richtext(sess, msgclass, 1, &recipient, message, NULL, 0); | |
1237 } | |
1238 | |
1239 /** | |
1240 * Wysy艂a wiadomo艣膰 formatowan膮. | |
1241 * | |
1242 * Zwraca losowy numer sekwencyjny, kt贸ry mo偶na zignorowa膰 albo wykorzysta膰 | |
1243 * do potwierdzenia. | |
1244 * | |
1245 * \param sess Struktura sesji | |
1246 * \param msgclass Klasa wiadomo艣ci | |
1247 * \param recipient Numer adresata | |
1248 * \param message Tre艣膰 wiadomo艣ci | |
1249 * \param format Informacje o formatowaniu | |
1250 * \param formatlen D艂ugo艣膰 informacji o formatowaniu | |
1251 * | |
1252 * \return Numer sekwencyjny wiadomo艣ci lub -1 w przypadku b艂臋du. | |
1253 * | |
1254 * \ingroup messages | |
1255 */ | |
1256 int gg_send_message_richtext(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message, const unsigned char *format, int formatlen) | |
1257 { | |
1258 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_send_message_richtext(%p, %d, %u, %p, %p, %d);\n", sess, msgclass, recipient, message, format, formatlen); | |
1259 | |
1260 return gg_send_message_confer_richtext(sess, msgclass, 1, &recipient, message, format, formatlen); | |
1261 } | |
1262 | |
1263 /** | |
1264 * Wysy艂a wiadomo艣膰 w ramach konferencji. | |
1265 * | |
1266 * Zwraca losowy numer sekwencyjny, kt贸ry mo偶na zignorowa膰 albo wykorzysta膰 | |
1267 * do potwierdzenia. | |
1268 * | |
1269 * \param sess Struktura sesji | |
1270 * \param msgclass Klasa wiadomo艣ci | |
1271 * \param recipients_count Liczba adresat贸w | |
1272 * \param recipients Wska藕nik do tablicy z numerami adresat贸w | |
1273 * \param message Tre艣膰 wiadomo艣ci | |
1274 * | |
1275 * \return Numer sekwencyjny wiadomo艣ci lub -1 w przypadku b艂臋du. | |
1276 * | |
1277 * \ingroup messages | |
1278 */ | |
1279 int gg_send_message_confer(struct gg_session *sess, int msgclass, int recipients_count, uin_t *recipients, const unsigned char *message) | |
1280 { | |
1281 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_send_message_confer(%p, %d, %d, %p, %p);\n", sess, msgclass, recipients_count, recipients, message); | |
1282 | |
1283 return gg_send_message_confer_richtext(sess, msgclass, recipients_count, recipients, message, NULL, 0); | |
1284 } | |
1285 | |
1286 /** | |
1287 * \internal Dodaje tekst na koniec bufora. | |
1288 * | |
1289 * \param dst Wska藕nik na bufor roboczy | |
1290 * \param pos Wska藕nik na aktualne po艂o偶enie w buforze roboczym | |
1291 * \param src Dodawany tekst | |
1292 * \param len D艂ugo艣膰 dodawanego tekstu | |
1293 */ | |
1294 static void gg_append(char *dst, int *pos, const void *src, int len) | |
1295 { | |
1296 if (dst != NULL) | |
1297 memcpy(&dst[*pos], src, len); | |
1298 | |
1299 *pos += len; | |
1300 } | |
1301 | |
1302 /** | |
1303 * \internal Zamienia tekst z formatowaniem Gadu-Gadu na HTML. | |
1304 * | |
1305 * \param dst Bufor wynikowy (mo偶e by膰 \c NULL) | |
1306 * \param utf_msg Tekst 藕r贸d艂owy | |
1307 * \param format Atrybuty tekstu 藕r贸d艂owego | |
1308 * \param format_len D艂ugo艣膰 bloku atrybut贸w tekstu 藕r贸d艂owego | |
1309 * | |
1310 * \note Dokleja \c \\0 na ko艅cu bufora wynikowego. | |
1311 * | |
1312 * \return D艂ugo艣膰 tekstu wynikowego bez \c \\0 (nawet je艣li \c dst to \c NULL). | |
1313 */ | |
1314 static int gg_convert_to_html(char *dst, const char *utf_msg, const unsigned char *format, int format_len) | |
1315 { | |
1316 const char span_fmt[] = "<span style=\"color:#%02x%02x%02x; font-family:'MS Shell Dlg 2'; font-size:9pt; \">"; | |
1317 const int span_len = 75; | |
1318 const char img_fmt[] = "<img src=\"%02x%02x%02x%02x%02x%02x%02x%02x\">"; | |
1319 const int img_len = 28; | |
1320 int char_pos = 0; | |
1321 int format_idx = 3; | |
1322 unsigned char old_attr = 0; | |
1323 const unsigned char *color = (const unsigned char*) "\x00\x00\x00"; | |
1324 int len, i; | |
1325 | |
1326 len = 0; | |
1327 | |
1328 for (i = 0; utf_msg[i] != 0; i++) { | |
1329 unsigned char attr; | |
1330 int attr_pos; | |
1331 | |
1332 if (format_idx + 3 <= format_len) { | |
1333 attr_pos = format[format_idx] | (format[format_idx + 1] << 8); | |
1334 attr = format[format_idx + 2]; | |
1335 } else { | |
1336 attr_pos = -1; | |
1337 attr = 0; | |
1338 } | |
1339 | |
1340 if (attr_pos == char_pos) { | |
1341 format_idx += 3; | |
1342 | |
1343 if ((attr & (GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR)) != 0) { | |
1344 if (char_pos != 0) { | |
1345 if ((old_attr & GG_FONT_UNDERLINE) != 0) | |
1346 gg_append(dst, &len, "</u>", 4); | |
1347 | |
1348 if ((old_attr & GG_FONT_ITALIC) != 0) | |
1349 gg_append(dst, &len, "</i>", 4); | |
1350 | |
1351 if ((old_attr & GG_FONT_BOLD) != 0) | |
1352 gg_append(dst, &len, "</b>", 4); | |
1353 | |
1354 gg_append(dst, &len, "</span>", 7); | |
1355 } | |
1356 | |
1357 if (((attr & GG_FONT_COLOR) != 0) && (format_idx + 3 <= format_len)) { | |
1358 color = &format[format_idx]; | |
1359 format_idx += 3; | |
1360 } else { | |
1361 color = (const unsigned char*) "\x00\x00\x00"; | |
1362 } | |
1363 | |
1364 if (dst != NULL) | |
1365 sprintf(&dst[len], span_fmt, color[0], color[1], color[2]); | |
1366 len += span_len; | |
1367 } else if (char_pos == 0) { | |
1368 if (dst != NULL) | |
1369 sprintf(&dst[len], span_fmt, 0, 0, 0); | |
1370 len += span_len; | |
1371 } | |
1372 | |
1373 if ((attr & GG_FONT_BOLD) != 0) | |
1374 gg_append(dst, &len, "<b>", 3); | |
1375 | |
1376 if ((attr & GG_FONT_ITALIC) != 0) | |
1377 gg_append(dst, &len, "<i>", 3); | |
1378 | |
1379 if ((attr & GG_FONT_UNDERLINE) != 0) | |
1380 gg_append(dst, &len, "<u>", 3); | |
1381 | |
1382 if (((attr & GG_FONT_IMAGE) != 0) && (format_idx + 10 <= format_len)) { | |
1383 if (dst != NULL) { | |
1384 sprintf(&dst[len], img_fmt, | |
1385 format[format_idx + 9], | |
1386 format[format_idx + 8], | |
1387 format[format_idx + 7], | |
1388 format[format_idx + 6], | |
1389 format[format_idx + 5], | |
1390 format[format_idx + 4], | |
1391 format[format_idx + 3], | |
1392 format[format_idx + 2]); | |
1393 } | |
1394 | |
1395 len += img_len; | |
1396 format_idx += 10; | |
1397 } | |
1398 | |
1399 old_attr = attr; | |
1400 } else if (i == 0) { | |
1401 if (dst != NULL) | |
1402 sprintf(&dst[len], span_fmt, 0, 0, 0); | |
1403 | |
1404 len += span_len; | |
1405 } | |
1406 | |
1407 switch (utf_msg[i]) { | |
1408 case '&': | |
1409 gg_append(dst, &len, "&", 5); | |
1410 break; | |
1411 case '<': | |
1412 gg_append(dst, &len, "<", 4); | |
1413 break; | |
1414 case '>': | |
1415 gg_append(dst, &len, ">", 4); | |
1416 break; | |
1417 case '\'': | |
1418 gg_append(dst, &len, "'", 6); | |
1419 break; | |
1420 case '\"': | |
1421 gg_append(dst, &len, """, 6); | |
1422 break; | |
1423 case '\n': | |
1424 gg_append(dst, &len, "<br>", 4); | |
1425 break; | |
1426 case '\r': | |
1427 break; | |
1428 default: | |
1429 if (dst != NULL) | |
1430 dst[len] = utf_msg[i]; | |
1431 len++; | |
1432 } | |
1433 | |
1434 /* Sprawd藕, czy bajt nie jest kontynuacj膮 znaku unikodowego. */ | |
1435 | |
1436 if ((utf_msg[i] & 0xc0) != 0xc0) | |
1437 char_pos++; | |
1438 } | |
1439 | |
1440 if ((old_attr & GG_FONT_UNDERLINE) != 0) | |
1441 gg_append(dst, &len, "</u>", 4); | |
1442 | |
1443 if ((old_attr & GG_FONT_ITALIC) != 0) | |
1444 gg_append(dst, &len, "</i>", 4); | |
1445 | |
1446 if ((old_attr & GG_FONT_BOLD) != 0) | |
1447 gg_append(dst, &len, "</b>", 4); | |
1448 | |
1449 /* Dla pustych tekst贸w dodaj pusty <span>. */ | |
1450 | |
1451 if (i == 0) { | |
1452 if (dst != NULL) | |
1453 sprintf(&dst[len], span_fmt, 0, 0, 0); | |
1454 | |
1455 len += span_len; | |
1456 } | |
1457 | |
1458 gg_append(dst, &len, "</span>", 7); | |
1459 | |
1460 if (dst != NULL) | |
1461 dst[len] = 0; | |
1462 | |
1463 return len; | |
1464 } | |
1465 | |
1466 /** | |
1467 * Wysy艂a wiadomo艣膰 formatowan膮 w ramach konferencji. | |
1468 * | |
1469 * Zwraca losowy numer sekwencyjny, kt贸ry mo偶na zignorowa膰 albo wykorzysta膰 | |
1470 * do potwierdzenia. | |
1471 * | |
1472 * \param sess Struktura sesji | |
1473 * \param msgclass Klasa wiadomo艣ci | |
1474 * \param recipients_count Liczba adresat贸w | |
1475 * \param recipients Wska藕nik do tablicy z numerami adresat贸w | |
1476 * \param message Tre艣膰 wiadomo艣ci | |
1477 * \param format Informacje o formatowaniu | |
1478 * \param formatlen D艂ugo艣膰 informacji o formatowaniu | |
1479 * | |
1480 * \return Numer sekwencyjny wiadomo艣ci lub -1 w przypadku b艂臋du. | |
1481 * | |
1482 * \ingroup messages | |
1483 */ | |
1484 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) | |
1485 { | |
1486 struct gg_send_msg s; | |
1487 struct gg_send_msg80 s80; | |
1488 struct gg_msg_recipients r; | |
1489 char *cp_msg = NULL; | |
1490 char *utf_msg = NULL; | |
1491 char *html_msg = NULL; | |
1492 int seq_no; | |
1493 int i, j, k; | |
1494 uin_t *recps; | |
1495 | |
1496 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_send_message_confer_richtext(%p, %d, %d, %p, %p, %p, %d);\n", sess, msgclass, recipients_count, recipients, message, format, formatlen); | |
1497 | |
1498 if (!sess) { | |
1499 errno = EFAULT; | |
1500 return -1; | |
1501 } | |
1502 | |
1503 if (sess->state != GG_STATE_CONNECTED) { | |
1504 errno = ENOTCONN; | |
1505 return -1; | |
1506 } | |
1507 | |
1508 if (message == NULL || recipients_count <= 0 || recipients_count > 0xffff || (recipients_count != 1 && recipients == NULL)) { | |
1509 errno = EINVAL; | |
1510 return -1; | |
1511 } | |
1512 | |
1513 if (sess->encoding == GG_ENCODING_UTF8) { | |
1514 if (!(cp_msg = gg_utf8_to_cp((const char *) message))) | |
1515 return -1; | |
1516 | |
1517 utf_msg = (char*) message; | |
1518 } else { | |
1519 if (sess->protocol_version >= 0x2d) { | |
1520 if (!(utf_msg = gg_cp_to_utf8((const char *) message))) | |
1521 return -1; | |
1522 } | |
1523 | |
1524 cp_msg = (char*) message; | |
1525 } | |
1526 | |
1527 if (sess->protocol_version < 0x2d) { | |
1528 if (!sess->seq) | |
1529 sess->seq = 0x01740000 | (rand() & 0xffff); | |
1530 seq_no = sess->seq; | |
1531 sess->seq += (rand() % 0x300) + 0x300; | |
1532 | |
1533 s.msgclass = gg_fix32(msgclass); | |
1534 s.seq = gg_fix32(seq_no); | |
1535 } else { | |
1536 int len; | |
1537 | |
1538 // Drobne odchylenie od protoko艂u. Je艣li wysy艂amy kilka | |
1539 // wiadomo艣ci w ci膮gu jednej sekundy, zwi臋kszamy poprzedni膮 | |
1540 // warto艣膰, 偶eby ka偶da wiadomo艣膰 mia艂a unikalny numer. | |
1541 | |
1542 seq_no = time(NULL); | |
1543 | |
1544 if (seq_no <= sess->seq) | |
1545 seq_no = sess->seq + 1; | |
1546 | |
1547 sess->seq = seq_no; | |
1548 | |
1549 if (format == NULL || formatlen < 3) { | |
1550 format = (unsigned char*) "\x02\x06\x00\x00\x00\x08\x00\x00\x00"; | |
1551 formatlen = 9; | |
1552 } | |
1553 | |
1554 len = gg_convert_to_html(NULL, utf_msg, format, formatlen); | |
1555 | |
1556 html_msg = malloc(len + 1); | |
1557 | |
1558 if (html_msg == NULL) { | |
1559 seq_no = -1; | |
1560 goto cleanup; | |
1561 } | |
1562 | |
1563 gg_convert_to_html(html_msg, utf_msg, format, formatlen); | |
1564 | |
1565 s80.seq = gg_fix32(seq_no); | |
1566 s80.msgclass = gg_fix32(msgclass); | |
1567 s80.offset_plain = gg_fix32(sizeof(s80) + strlen(html_msg) + 1); | |
1568 s80.offset_attr = gg_fix32(sizeof(s80) + strlen(html_msg) + 1 + strlen(cp_msg) + 1); | |
1569 } | |
1570 | |
1571 if (recipients_count > 1) { | |
1572 r.flag = 0x01; | |
1573 r.count = gg_fix32(recipients_count - 1); | |
1574 | |
1575 recps = malloc(sizeof(uin_t) * recipients_count); | |
1576 | |
1577 if (!recps) { | |
1578 seq_no = -1; | |
1579 goto cleanup; | |
1580 } | |
1581 | |
1582 for (i = 0; i < recipients_count; i++) { | |
1583 for (j = 0, k = 0; j < recipients_count; j++) { | |
1584 if (recipients[j] != recipients[i]) { | |
1585 recps[k] = gg_fix32(recipients[j]); | |
1586 k++; | |
1587 } | |
1588 } | |
1589 | |
1590 if (sess->protocol_version < 0x2d) { | |
1591 s.recipient = gg_fix32(recipients[i]); | |
1592 | |
1593 if (gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), cp_msg, strlen(cp_msg) + 1, &r, sizeof(r), recps, (recipients_count - 1) * sizeof(uin_t), format, formatlen, NULL) == -1) | |
1594 seq_no = -1; | |
1595 } else { | |
1596 s80.recipient = gg_fix32(recipients[i]); | |
1597 | |
1598 if (gg_send_packet(sess, GG_SEND_MSG80, &s80, sizeof(s80), html_msg, strlen(html_msg) + 1, cp_msg, strlen(cp_msg) + 1, &r, sizeof(r), recps, (recipients_count - 1) * sizeof(uin_t), format, formatlen, NULL) == -1) | |
1599 seq_no = -1; | |
1600 } | |
1601 } | |
1602 | |
1603 free(recps); | |
1604 } else { | |
1605 if (sess->protocol_version < 0x2d) { | |
1606 s.recipient = gg_fix32(recipients[0]); | |
1607 | |
1608 if (gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), cp_msg, strlen(cp_msg) + 1, format, formatlen, NULL) == -1) | |
1609 seq_no = -1; | |
1610 } else { | |
1611 s80.recipient = gg_fix32(recipients[0]); | |
1612 | |
1613 if (gg_send_packet(sess, GG_SEND_MSG80, &s80, sizeof(s80), html_msg, strlen(html_msg) + 1, cp_msg, strlen(cp_msg) + 1, format, formatlen, NULL) == -1) | |
1614 seq_no = -1; | |
1615 } | |
1616 } | |
1617 | |
1618 cleanup: | |
1619 if (cp_msg != (char*) message) | |
1620 free(cp_msg); | |
1621 | |
1622 if (utf_msg != (char*) message) | |
1623 free(utf_msg); | |
1624 | |
1625 free(html_msg); | |
1626 | |
1627 return seq_no; | |
1628 } | |
1629 | |
1630 /** | |
1631 * Wysy艂a wiadomo艣膰 binarn膮 przeznaczon膮 dla klienta. | |
1632 * | |
1633 * Wiadomo艣ci mi臋dzy klientami przesy艂a si臋 np. w celu wywo艂ania zwrotnego | |
1634 * po艂膮czenia bezpo艣redniego. Funkcja zwraca losowy numer sekwencyjny, | |
1635 * kt贸ry mo偶na zignorowa膰 albo wykorzysta膰 do potwierdzenia. | |
1636 * | |
1637 * \param sess Struktura sesji | |
1638 * \param msgclass Klasa wiadomo艣ci | |
1639 * \param recipient Numer adresata | |
1640 * \param message Tre艣膰 wiadomo艣ci | |
1641 * \param message_len D艂ugo艣膰 wiadomo艣ci | |
1642 * | |
1643 * \return Numer sekwencyjny wiadomo艣ci lub -1 w przypadku b艂臋du. | |
1644 * | |
1645 * \ingroup messages | |
1646 */ | |
1647 int gg_send_message_ctcp(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message, int message_len) | |
1648 { | |
1649 struct gg_send_msg s; | |
1650 | |
1651 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_send_message_ctcp(%p, %d, %u, ...);\n", sess, msgclass, recipient); | |
1652 | |
1653 if (!sess) { | |
1654 errno = EFAULT; | |
1655 return -1; | |
1656 } | |
1657 | |
1658 if (sess->state != GG_STATE_CONNECTED) { | |
1659 errno = ENOTCONN; | |
1660 return -1; | |
1661 } | |
1662 | |
1663 s.recipient = gg_fix32(recipient); | |
1664 s.seq = gg_fix32(0); | |
1665 s.msgclass = gg_fix32(msgclass); | |
1666 | |
1667 return gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), message, message_len, NULL); | |
1668 } | |
1669 | |
1670 /** | |
1671 * Wysy艂a 偶膮danie obrazka o podanych parametrach. | |
1672 * | |
1673 * Wiadomo艣ci obrazkowe nie zawieraj膮 samych obrazk贸w, a tylko ich rozmiary | |
1674 * i sumy kontrolne. Odbiorca najpierw szuka obrazk贸w w swojej pami臋ci | |
1675 * podr臋cznej i dopiero gdy ich nie znajdzie, wysy艂a 偶膮danie do nadawcy. | |
1676 * Wynik zostanie przekazany zdarzeniem \c GG_EVENT_IMAGE_REPLY. | |
1677 * | |
1678 * \param sess Struktura sesji | |
1679 * \param recipient Numer adresata | |
1680 * \param size Rozmiar obrazka w bajtach | |
1681 * \param crc32 Suma kontrola obrazka | |
1682 * | |
1683 * \return 0 je艣li si臋 powiod艂o, -1 w przypadku b艂臋du | |
1684 * | |
1685 * \ingroup messages | |
1378 */ | 1686 */ |
1379 int gg_image_request(struct gg_session *sess, uin_t recipient, int size, uint32_t crc32) | 1687 int gg_image_request(struct gg_session *sess, uin_t recipient, int size, uint32_t crc32) |
1380 { | 1688 { |
1381 struct gg_send_msg s; | 1689 struct gg_send_msg s; |
1382 struct gg_msg_image_request r; | 1690 struct gg_msg_image_request r; |
1383 char dummy = 0; | 1691 char dummy = 0; |
1384 int res; | 1692 int res; |
1385 | 1693 |
1386 gg_debug(GG_DEBUG_FUNCTION, "** gg_image_request(%p, %d, %u, 0x%.4x);\n", sess, recipient, size, crc32); | 1694 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_image_request(%p, %d, %u, 0x%.4x);\n", sess, recipient, size, crc32); |
1387 | 1695 |
1388 if (!sess) { | 1696 if (!sess) { |
1389 errno = EFAULT; | 1697 errno = EFAULT; |
1390 return -1; | 1698 return -1; |
1391 } | 1699 } |
1392 | 1700 |
1393 if (sess->state != GG_STATE_CONNECTED) { | 1701 if (sess->state != GG_STATE_CONNECTED) { |
1394 errno = ENOTCONN; | 1702 errno = ENOTCONN; |
1395 return -1; | 1703 return -1; |
1396 } | 1704 } |
1397 | 1705 |
1405 s.msgclass = gg_fix32(GG_CLASS_MSG); | 1713 s.msgclass = gg_fix32(GG_CLASS_MSG); |
1406 | 1714 |
1407 r.flag = 0x04; | 1715 r.flag = 0x04; |
1408 r.size = gg_fix32(size); | 1716 r.size = gg_fix32(size); |
1409 r.crc32 = gg_fix32(crc32); | 1717 r.crc32 = gg_fix32(crc32); |
1410 | 1718 |
1411 res = gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), &dummy, 1, &r, sizeof(r), NULL); | 1719 res = gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), &dummy, 1, &r, sizeof(r), NULL); |
1412 | 1720 |
1413 if (!res) { | 1721 if (!res) { |
1414 struct gg_image_queue *q = malloc(sizeof(*q)); | 1722 struct gg_image_queue *q = malloc(sizeof(*q)); |
1415 char *buf; | 1723 char *buf; |
1416 | 1724 |
1417 if (!q) { | 1725 if (!q) { |
1418 gg_debug(GG_DEBUG_MISC, "// gg_image_request() not enough memory for image queue\n"); | 1726 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_image_request() not enough memory for image queue\n"); |
1419 return -1; | 1727 return -1; |
1420 } | 1728 } |
1421 | 1729 |
1422 buf = malloc(size); | 1730 buf = malloc(size); |
1423 if (size && !buf) | 1731 if (size && !buf) |
1424 { | 1732 { |
1425 gg_debug(GG_DEBUG_MISC, "// gg_image_request() not enough memory for image\n"); | 1733 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_image_request() not enough memory for image\n"); |
1426 free(q); | 1734 free(q); |
1427 return -1; | 1735 return -1; |
1428 } | 1736 } |
1429 | 1737 |
1430 memset(q, 0, sizeof(*q)); | 1738 memset(q, 0, sizeof(*q)); |
1447 } | 1755 } |
1448 | 1756 |
1449 return res; | 1757 return res; |
1450 } | 1758 } |
1451 | 1759 |
1452 /* | 1760 /** |
1453 * gg_image_reply() | 1761 * Wysy艂a 偶膮dany obrazek. |
1454 * | 1762 * |
1455 * wysy砤 勘dany obrazek. | 1763 * \param sess Struktura sesji |
1456 * | 1764 * \param recipient Numer adresata |
1457 * - sess - opis sesji | 1765 * \param filename Nazwa pliku |
1458 * - recipient - numer adresata | 1766 * \param image Bufor z obrazkiem |
1459 * - filename - nazwa pliku | 1767 * \param size Rozmiar obrazka |
1460 * - image - bufor z obrazkiem | 1768 * |
1461 * - size - rozmiar obrazka | 1769 * \return 0 je艣li si臋 powiod艂o, -1 w przypadku b艂臋du |
1462 * | 1770 * |
1463 * 0/-1 | 1771 * \ingroup messages |
1464 */ | 1772 */ |
1465 int gg_image_reply(struct gg_session *sess, uin_t recipient, const char *filename, const unsigned char *image, int size) | 1773 int gg_image_reply(struct gg_session *sess, uin_t recipient, const char *filename, const char *image, int size) |
1466 { | 1774 { |
1467 struct gg_msg_image_reply *r; | 1775 struct gg_msg_image_reply *r; |
1468 struct gg_send_msg s; | 1776 struct gg_send_msg s; |
1469 const char *tmp; | 1777 const char *tmp; |
1470 char buf[1910]; | 1778 char buf[1910]; |
1471 int res = -1; | 1779 int res = -1; |
1472 | 1780 |
1473 gg_debug(GG_DEBUG_FUNCTION, "** gg_image_reply(%p, %d, \"%s\", %p, %d);\n", sess, recipient, filename, image, size); | 1781 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_image_reply(%p, %d, \"%s\", %p, %d);\n", sess, recipient, filename, image, size); |
1474 | 1782 |
1475 if (!sess || !filename || !image) { | 1783 if (!sess || !filename || !image) { |
1476 errno = EFAULT; | 1784 errno = EFAULT; |
1477 return -1; | 1785 return -1; |
1478 } | 1786 } |
1485 if (size < 0) { | 1793 if (size < 0) { |
1486 errno = EINVAL; | 1794 errno = EINVAL; |
1487 return -1; | 1795 return -1; |
1488 } | 1796 } |
1489 | 1797 |
1490 /* wytnij 禼ie縦i, zostaw tylko nazw pliku */ | 1798 /* wytnij 艣cie偶ki, zostaw tylko nazw臋 pliku */ |
1491 while ((tmp = strrchr(filename, '/')) || (tmp = strrchr(filename, '\\'))) | 1799 while ((tmp = strrchr(filename, '/')) || (tmp = strrchr(filename, '\\'))) |
1492 filename = tmp + 1; | 1800 filename = tmp + 1; |
1493 | 1801 |
1494 if (strlen(filename) < 1 || strlen(filename) > 1024) { | 1802 if (strlen(filename) < 1 || strlen(filename) > 1024) { |
1495 errno = EINVAL; | 1803 errno = EINVAL; |
1496 return -1; | 1804 return -1; |
1497 } | 1805 } |
1498 | 1806 |
1499 s.recipient = gg_fix32(recipient); | 1807 s.recipient = gg_fix32(recipient); |
1500 s.seq = gg_fix32(0); | 1808 s.seq = gg_fix32(0); |
1501 s.msgclass = gg_fix32(GG_CLASS_MSG); | 1809 s.msgclass = gg_fix32(GG_CLASS_MSG); |
1502 | 1810 |
1503 buf[0] = 0; | 1811 buf[0] = 0; |
1504 r = (void*) &buf[1]; | 1812 r = (void*) &buf[1]; |
1505 | 1813 |
1506 r->flag = 0x05; | 1814 r->flag = 0x05; |
1507 r->size = gg_fix32(size); | 1815 r->size = gg_fix32(size); |
1508 r->crc32 = gg_fix32(gg_crc32(0, image, size)); | 1816 r->crc32 = gg_fix32(gg_crc32(0, (unsigned char*) image, size)); |
1509 | 1817 |
1510 while (size > 0) { | 1818 while (size > 0) { |
1511 size_t buflen, chunklen; | 1819 int buflen, chunklen; |
1512 | 1820 |
1513 /* \0 + struct gg_msg_image_reply */ | 1821 /* \0 + struct gg_msg_image_reply */ |
1514 buflen = sizeof(struct gg_msg_image_reply) + 1; | 1822 buflen = sizeof(struct gg_msg_image_reply) + 1; |
1515 | 1823 |
1516 /* w pierwszym kawa砶u jest nazwa pliku */ | 1824 /* w pierwszym kawa艂ku jest nazwa pliku */ |
1517 if (r->flag == 0x05) { | 1825 if (r->flag == 0x05) { |
1518 strcpy(buf + buflen, filename); | 1826 strcpy(buf + buflen, filename); |
1519 buflen += strlen(filename) + 1; | 1827 buflen += strlen(filename) + 1; |
1520 } | 1828 } |
1521 | 1829 |
1522 chunklen = ((size_t)size >= sizeof(buf) - buflen) ? (sizeof(buf) - buflen) : (size_t)size; | 1830 chunklen = (size >= sizeof(buf) - buflen) ? (sizeof(buf) - buflen) : size; |
1523 | 1831 |
1524 memcpy(buf + buflen, image, chunklen); | 1832 memcpy(buf + buflen, image, chunklen); |
1525 size -= chunklen; | 1833 size -= chunklen; |
1526 image += chunklen; | 1834 image += chunklen; |
1527 | 1835 |
1528 res = gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), buf, buflen + chunklen, NULL); | 1836 res = gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), buf, buflen + chunklen, NULL); |
1529 | 1837 |
1530 if (res == -1) | 1838 if (res == -1) |
1531 break; | 1839 break; |
1532 | 1840 |
1534 } | 1842 } |
1535 | 1843 |
1536 return res; | 1844 return res; |
1537 } | 1845 } |
1538 | 1846 |
1539 /* | 1847 /** |
1540 * gg_send_message_ctcp() | 1848 * Wysy艂a do serwera list臋 kontakt贸w. |
1541 * | 1849 * |
1542 * wysy砤 wiadomo舵 do innego u縴tkownika. zwraca losowy numer | 1850 * Funkcja informuje serwer o li艣cie kontakt贸w, kt贸rych statusy b臋d膮 |
1543 * sekwencyjny, kt髍y mo縩a zignorowa albo wykorzysta do potwierdzenia. | 1851 * obserwowane lub kontakt贸w, kt贸re bed膮 blokowane. Dla ka偶dego z \c count |
1544 * | 1852 * kontakt贸w tablica \c userlist zawiera numer, a tablica \c types rodzaj |
1545 * - sess - opis sesji | 1853 * kontaktu (\c GG_USER_NORMAL, \c GG_USER_OFFLINE, \c GG_USER_BLOCKED). |
1546 * - msgclass - rodzaj wiadomo禼i | 1854 * |
1547 * - recipient - numer adresata | 1855 * List臋 kontakt贸w nale偶y \b zawsze wysy艂a膰 po po艂膮czeniu, nawet je艣li |
1548 * - message - tre舵 wiadomo禼i | 1856 * jest pusta. |
1549 * - message_len - d硊go舵 | 1857 * |
1550 * | 1858 * \param sess Struktura sesji |
1551 * numer sekwencyjny wiadomo禼i lub -1 w przypadku b酬du. | 1859 * \param userlist Wska藕nik do tablicy numer贸w kontakt贸w |
1552 */ | 1860 * \param types Wska藕nik do tablicy rodzaj贸w kontakt贸w |
1553 int gg_send_message_ctcp(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message, int message_len) | 1861 * \param count Liczba kontakt贸w |
1554 { | 1862 * |
1555 struct gg_send_msg s; | 1863 * \return 0 je艣li si臋 powiod艂o, -1 w przypadku b艂臋du |
1556 | 1864 * |
1557 gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message_ctcp(%p, %d, %u, ...);\n", sess, msgclass, recipient); | 1865 * \ingroup contacts |
1558 | |
1559 if (!sess) { | |
1560 errno = EFAULT; | |
1561 return -1; | |
1562 } | |
1563 | |
1564 if (sess->state != GG_STATE_CONNECTED) { | |
1565 errno = ENOTCONN; | |
1566 return -1; | |
1567 } | |
1568 | |
1569 s.recipient = gg_fix32(recipient); | |
1570 s.seq = gg_fix32(0); | |
1571 s.msgclass = gg_fix32(msgclass); | |
1572 | |
1573 return gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), message, message_len, NULL); | |
1574 } | |
1575 | |
1576 /* | |
1577 * gg_send_message() | |
1578 * | |
1579 * wysy砤 wiadomo舵 do innego u縴tkownika. zwraca losowy numer | |
1580 * sekwencyjny, kt髍y mo縩a zignorowa albo wykorzysta do potwierdzenia. | |
1581 * | |
1582 * - sess - opis sesji | |
1583 * - msgclass - rodzaj wiadomo禼i | |
1584 * - recipient - numer adresata | |
1585 * - message - tre舵 wiadomo禼i | |
1586 * | |
1587 * numer sekwencyjny wiadomo禼i lub -1 w przypadku b酬du. | |
1588 */ | |
1589 int gg_send_message(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message) | |
1590 { | |
1591 gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message(%p, %d, %u, %p)\n", sess, msgclass, recipient, message); | |
1592 | |
1593 return gg_send_message_richtext(sess, msgclass, recipient, message, NULL, 0); | |
1594 } | |
1595 | |
1596 /* | |
1597 * gg_send_message_richtext() | |
1598 * | |
1599 * wysy砤 kolorow wiadomo舵 do innego u縴tkownika. zwraca losowy numer | |
1600 * sekwencyjny, kt髍y mo縩a zignorowa albo wykorzysta do potwierdzenia. | |
1601 * | |
1602 * - sess - opis sesji | |
1603 * - msgclass - rodzaj wiadomo禼i | |
1604 * - recipient - numer adresata | |
1605 * - message - tre舵 wiadomo禼i | |
1606 * - format - informacje o formatowaniu | |
1607 * - formatlen - d硊go舵 informacji o formatowaniu | |
1608 * | |
1609 * numer sekwencyjny wiadomo禼i lub -1 w przypadku b酬du. | |
1610 */ | |
1611 int gg_send_message_richtext(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message, const unsigned char *format, int formatlen) | |
1612 { | |
1613 struct gg_send_msg s; | |
1614 | |
1615 gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message_richtext(%p, %d, %u, %p, %p, %d);\n", sess, msgclass, recipient, message, format, formatlen); | |
1616 | |
1617 if (!sess) { | |
1618 errno = EFAULT; | |
1619 return -1; | |
1620 } | |
1621 | |
1622 if (sess->state != GG_STATE_CONNECTED) { | |
1623 errno = ENOTCONN; | |
1624 return -1; | |
1625 } | |
1626 | |
1627 if (!message) { | |
1628 errno = EFAULT; | |
1629 return -1; | |
1630 } | |
1631 | |
1632 s.recipient = gg_fix32(recipient); | |
1633 if (!sess->seq) | |
1634 sess->seq = 0x01740000 | (rand() & 0xffff); | |
1635 s.seq = gg_fix32(sess->seq); | |
1636 s.msgclass = gg_fix32(msgclass); | |
1637 sess->seq += (rand() % 0x300) + 0x300; | |
1638 | |
1639 if (gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), message, strlen((const char *)message) + 1, format, formatlen, NULL) == -1) | |
1640 return -1; | |
1641 | |
1642 return gg_fix32(s.seq); | |
1643 } | |
1644 | |
1645 /* | |
1646 * gg_send_message_confer() | |
1647 * | |
1648 * wysy砤 wiadomo舵 do kilku u縴tkownikow (konferencja). zwraca losowy numer | |
1649 * sekwencyjny, kt髍y mo縩a zignorowa albo wykorzysta do potwierdzenia. | |
1650 * | |
1651 * - sess - opis sesji | |
1652 * - msgclass - rodzaj wiadomo禼i | |
1653 * - recipients_count - ilo舵 adresat體 | |
1654 * - recipients - numerki adresat體 | |
1655 * - message - tre舵 wiadomo禼i | |
1656 * | |
1657 * numer sekwencyjny wiadomo禼i lub -1 w przypadku b酬du. | |
1658 */ | |
1659 int gg_send_message_confer(struct gg_session *sess, int msgclass, int recipients_count, uin_t *recipients, const unsigned char *message) | |
1660 { | |
1661 gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message_confer(%p, %d, %d, %p, %p);\n", sess, msgclass, recipients_count, recipients, message); | |
1662 | |
1663 return gg_send_message_confer_richtext(sess, msgclass, recipients_count, recipients, message, NULL, 0); | |
1664 } | |
1665 | |
1666 /* | |
1667 * gg_send_message_confer_richtext() | |
1668 * | |
1669 * wysy砤 kolorow wiadomo舵 do kilku u縴tkownikow (konferencja). zwraca | |
1670 * losowy numer sekwencyjny, kt髍y mo縩a zignorowa albo wykorzysta do | |
1671 * potwierdzenia. | |
1672 * | |
1673 * - sess - opis sesji | |
1674 * - msgclass - rodzaj wiadomo禼i | |
1675 * - recipients_count - ilo舵 adresat體 | |
1676 * - recipients - numerki adresat體 | |
1677 * - message - tre舵 wiadomo禼i | |
1678 * - format - informacje o formatowaniu | |
1679 * - formatlen - d硊go舵 informacji o formatowaniu | |
1680 * | |
1681 * numer sekwencyjny wiadomo禼i lub -1 w przypadku b酬du. | |
1682 */ | |
1683 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) | |
1684 { | |
1685 struct gg_send_msg s; | |
1686 struct gg_msg_recipients r; | |
1687 int i, j, k; | |
1688 uin_t *recps; | |
1689 | |
1690 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); | |
1691 | |
1692 if (!sess) { | |
1693 errno = EFAULT; | |
1694 return -1; | |
1695 } | |
1696 | |
1697 if (sess->state != GG_STATE_CONNECTED) { | |
1698 errno = ENOTCONN; | |
1699 return -1; | |
1700 } | |
1701 | |
1702 if (!message || recipients_count <= 0 || recipients_count > 0xffff || !recipients) { | |
1703 errno = EINVAL; | |
1704 return -1; | |
1705 } | |
1706 | |
1707 r.flag = 0x01; | |
1708 r.count = gg_fix32(recipients_count - 1); | |
1709 | |
1710 if (!sess->seq) | |
1711 sess->seq = 0x01740000 | (rand() & 0xffff); | |
1712 s.seq = gg_fix32(sess->seq); | |
1713 s.msgclass = gg_fix32(msgclass); | |
1714 | |
1715 recps = malloc(sizeof(uin_t) * recipients_count); | |
1716 if (!recps) | |
1717 return -1; | |
1718 | |
1719 for (i = 0; i < recipients_count; i++) { | |
1720 | |
1721 s.recipient = gg_fix32(recipients[i]); | |
1722 | |
1723 for (j = 0, k = 0; j < recipients_count; j++) | |
1724 if (recipients[j] != recipients[i]) { | |
1725 recps[k] = gg_fix32(recipients[j]); | |
1726 k++; | |
1727 } | |
1728 | |
1729 if (!i) | |
1730 sess->seq += (rand() % 0x300) + 0x300; | |
1731 | |
1732 if (gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), message, strlen((const char *)message) + 1, &r, sizeof(r), recps, (recipients_count - 1) * sizeof(uin_t), format, formatlen, NULL) == -1) { | |
1733 free(recps); | |
1734 return -1; | |
1735 } | |
1736 } | |
1737 | |
1738 free(recps); | |
1739 | |
1740 return gg_fix32(s.seq); | |
1741 } | |
1742 | |
1743 /* | |
1744 * gg_ping() | |
1745 * | |
1746 * wysy砤 do serwera pakiet ping. | |
1747 * | |
1748 * - sess - opis sesji | |
1749 * | |
1750 * 0, -1. | |
1751 */ | |
1752 int gg_ping(struct gg_session *sess) | |
1753 { | |
1754 gg_debug(GG_DEBUG_FUNCTION, "** gg_ping(%p);\n", sess); | |
1755 | |
1756 if (!sess) { | |
1757 errno = EFAULT; | |
1758 return -1; | |
1759 } | |
1760 | |
1761 if (sess->state != GG_STATE_CONNECTED) { | |
1762 errno = ENOTCONN; | |
1763 return -1; | |
1764 } | |
1765 | |
1766 return gg_send_packet(sess, GG_PING, NULL); | |
1767 } | |
1768 | |
1769 /* | |
1770 * gg_notify_ex() | |
1771 * | |
1772 * wysy砤 serwerowi list kontakt體 (wraz z odpowiadaj眂ymi im typami user體), | |
1773 * dzi阫i czemu wie, czyj stan nas interesuje. | |
1774 * | |
1775 * - sess - opis sesji | |
1776 * - userlist - wska糿ik do tablicy numer體 | |
1777 * - types - wska糿ik do tablicy typ體 u縴tkownik體 | |
1778 * - count - ilo舵 numerk體 | |
1779 * | |
1780 * 0, -1. | |
1781 */ | 1866 */ |
1782 int gg_notify_ex(struct gg_session *sess, uin_t *userlist, char *types, int count) | 1867 int gg_notify_ex(struct gg_session *sess, uin_t *userlist, char *types, int count) |
1783 { | 1868 { |
1784 struct gg_notify *n; | 1869 struct gg_notify *n; |
1785 uin_t *u; | 1870 uin_t *u; |
1786 char *t; | 1871 char *t; |
1787 int i, res = 0; | 1872 int i, res = 0; |
1788 | 1873 |
1789 gg_debug(GG_DEBUG_FUNCTION, "** gg_notify_ex(%p, %p, %p, %d);\n", sess, userlist, types, count); | 1874 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_notify_ex(%p, %p, %p, %d);\n", sess, userlist, types, count); |
1790 | 1875 |
1791 if (!sess) { | 1876 if (!sess) { |
1792 errno = EFAULT; | 1877 errno = EFAULT; |
1793 return -1; | 1878 return -1; |
1794 } | 1879 } |
1795 | 1880 |
1796 if (sess->state != GG_STATE_CONNECTED) { | 1881 if (sess->state != GG_STATE_CONNECTED) { |
1797 errno = ENOTCONN; | 1882 errno = ENOTCONN; |
1798 return -1; | 1883 return -1; |
1799 } | 1884 } |
1800 | 1885 |
1801 if (!userlist || !count) | 1886 if (!userlist || !count) |
1802 return gg_send_packet(sess, GG_LIST_EMPTY, NULL); | 1887 return gg_send_packet(sess, GG_LIST_EMPTY, NULL); |
1803 | 1888 |
1804 while (count > 0) { | 1889 while (count > 0) { |
1805 int part_count, packet_type; | 1890 int part_count, packet_type; |
1806 | 1891 |
1807 if (count > 400) { | 1892 if (count > 400) { |
1808 part_count = 400; | 1893 part_count = 400; |
1809 packet_type = GG_NOTIFY_FIRST; | 1894 packet_type = GG_NOTIFY_FIRST; |
1810 } else { | 1895 } else { |
1811 part_count = count; | 1896 part_count = count; |
1812 packet_type = GG_NOTIFY_LAST; | 1897 packet_type = GG_NOTIFY_LAST; |
1813 } | 1898 } |
1814 | 1899 |
1815 if (!(n = (struct gg_notify*) malloc(sizeof(*n) * part_count))) | 1900 if (!(n = (struct gg_notify*) malloc(sizeof(*n) * part_count))) |
1816 return -1; | 1901 return -1; |
1817 | 1902 |
1818 for (u = userlist, t = types, i = 0; i < part_count; u++, t++, i++) { | 1903 for (u = userlist, t = types, i = 0; i < part_count; u++, t++, i++) { |
1819 n[i].uin = gg_fix32(*u); | 1904 n[i].uin = gg_fix32(*u); |
1820 n[i].dunno1 = *t; | 1905 n[i].dunno1 = *t; |
1821 } | 1906 } |
1822 | 1907 |
1823 if (gg_send_packet(sess, packet_type, n, sizeof(*n) * part_count, NULL) == -1) { | 1908 if (gg_send_packet(sess, packet_type, n, sizeof(*n) * part_count, NULL) == -1) { |
1824 free(n); | 1909 free(n); |
1825 res = -1; | 1910 res = -1; |
1826 break; | 1911 break; |
1827 } | 1912 } |
1834 } | 1919 } |
1835 | 1920 |
1836 return res; | 1921 return res; |
1837 } | 1922 } |
1838 | 1923 |
1839 /* | 1924 /** |
1840 * gg_notify() | 1925 * Wysy艂a do serwera list臋 kontakt贸w. |
1841 * | 1926 * |
1842 * wysy砤 serwerowi list kontakt體, dzi阫i czemu wie, czyj stan nas | 1927 * Funkcja jest odpowiednikiem \c gg_notify_ex(), gdzie wszystkie kontakty |
1843 * interesuje. | 1928 * s膮 rodzaju \c GG_USER_NORMAL. |
1844 * | 1929 * |
1845 * - sess - opis sesji | 1930 * \param sess Struktura sesji |
1846 * - userlist - wska糿ik do tablicy numer體 | 1931 * \param userlist Wska藕nik do tablicy numer贸w kontakt贸w |
1847 * - count - ilo舵 numerk體 | 1932 * \param count Liczba kontakt贸w |
1848 * | 1933 * |
1849 * 0, -1. | 1934 * \return 0 je艣li si臋 powiod艂o, -1 w przypadku b艂臋du |
1935 * | |
1936 * \ingroup contacts | |
1850 */ | 1937 */ |
1851 int gg_notify(struct gg_session *sess, uin_t *userlist, int count) | 1938 int gg_notify(struct gg_session *sess, uin_t *userlist, int count) |
1852 { | 1939 { |
1853 struct gg_notify *n; | 1940 struct gg_notify *n; |
1854 uin_t *u; | 1941 uin_t *u; |
1855 int i, res = 0; | 1942 int i, res = 0; |
1856 | 1943 |
1857 gg_debug(GG_DEBUG_FUNCTION, "** gg_notify(%p, %p, %d);\n", sess, userlist, count); | 1944 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_notify(%p, %p, %d);\n", sess, userlist, count); |
1858 | 1945 |
1859 if (!sess) { | 1946 if (!sess) { |
1860 errno = EFAULT; | 1947 errno = EFAULT; |
1861 return -1; | 1948 return -1; |
1862 } | 1949 } |
1863 | 1950 |
1864 if (sess->state != GG_STATE_CONNECTED) { | 1951 if (sess->state != GG_STATE_CONNECTED) { |
1865 errno = ENOTCONN; | 1952 errno = ENOTCONN; |
1866 return -1; | 1953 return -1; |
1867 } | 1954 } |
1868 | 1955 |
1869 if (!userlist || !count) | 1956 if (!userlist || !count) |
1870 return gg_send_packet(sess, GG_LIST_EMPTY, NULL); | 1957 return gg_send_packet(sess, GG_LIST_EMPTY, NULL); |
1871 | 1958 |
1872 while (count > 0) { | 1959 while (count > 0) { |
1873 int part_count, packet_type; | 1960 int part_count, packet_type; |
1874 | 1961 |
1875 if (count > 400) { | 1962 if (count > 400) { |
1876 part_count = 400; | 1963 part_count = 400; |
1877 packet_type = GG_NOTIFY_FIRST; | 1964 packet_type = GG_NOTIFY_FIRST; |
1878 } else { | 1965 } else { |
1879 part_count = count; | 1966 part_count = count; |
1880 packet_type = GG_NOTIFY_LAST; | 1967 packet_type = GG_NOTIFY_LAST; |
1881 } | 1968 } |
1882 | 1969 |
1883 if (!(n = (struct gg_notify*) malloc(sizeof(*n) * part_count))) | 1970 if (!(n = (struct gg_notify*) malloc(sizeof(*n) * part_count))) |
1884 return -1; | 1971 return -1; |
1885 | 1972 |
1886 for (u = userlist, i = 0; i < part_count; u++, i++) { | 1973 for (u = userlist, i = 0; i < part_count; u++, i++) { |
1887 n[i].uin = gg_fix32(*u); | 1974 n[i].uin = gg_fix32(*u); |
1888 n[i].dunno1 = GG_USER_NORMAL; | 1975 n[i].dunno1 = GG_USER_NORMAL; |
1889 } | 1976 } |
1890 | 1977 |
1891 if (gg_send_packet(sess, packet_type, n, sizeof(*n) * part_count, NULL) == -1) { | 1978 if (gg_send_packet(sess, packet_type, n, sizeof(*n) * part_count, NULL) == -1) { |
1892 res = -1; | 1979 res = -1; |
1893 free(n); | 1980 free(n); |
1894 break; | 1981 break; |
1895 } | 1982 } |
1901 } | 1988 } |
1902 | 1989 |
1903 return res; | 1990 return res; |
1904 } | 1991 } |
1905 | 1992 |
1906 /* | 1993 /** |
1907 * gg_add_notify_ex() | 1994 * Dodaje kontakt. |
1908 * | 1995 * |
1909 * dodaje do listy kontakt體 dany numer w trakcie po潮czenia. | 1996 * Dodaje do listy kontakt贸w dany numer w trakcie po艂膮czenia. Aby zmieni膰 |
1910 * dodawanemu u縴tkownikowi okre秎amy jego typ (patrz protocol.html) | 1997 * rodzaj kontaktu (np. z normalnego na zablokowany), nale偶y najpierw usun膮膰 |
1911 * | 1998 * poprzedni rodzaj, poniewa偶 serwer operuje na maskach bitowych. |
1912 * - sess - opis sesji | 1999 * |
1913 * - uin - numer | 2000 * \param sess Struktura sesji |
1914 * - type - typ | 2001 * \param uin Numer kontaktu |
1915 * | 2002 * \param type Rodzaj kontaktu |
1916 * 0, -1. | 2003 * |
2004 * \return 0 je艣li si臋 powiod艂o, -1 w przypadku b艂臋du | |
2005 * | |
2006 * \ingroup contacts | |
1917 */ | 2007 */ |
1918 int gg_add_notify_ex(struct gg_session *sess, uin_t uin, char type) | 2008 int gg_add_notify_ex(struct gg_session *sess, uin_t uin, char type) |
1919 { | 2009 { |
1920 struct gg_add_remove a; | 2010 struct gg_add_remove a; |
1921 | 2011 |
1922 gg_debug(GG_DEBUG_FUNCTION, "** gg_add_notify_ex(%p, %u, %d);\n", sess, uin, type); | 2012 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_add_notify_ex(%p, %u, %d);\n", sess, uin, type); |
1923 | 2013 |
1924 if (!sess) { | 2014 if (!sess) { |
1925 errno = EFAULT; | 2015 errno = EFAULT; |
1926 return -1; | 2016 return -1; |
1927 } | 2017 } |
1928 | 2018 |
1929 if (sess->state != GG_STATE_CONNECTED) { | 2019 if (sess->state != GG_STATE_CONNECTED) { |
1930 errno = ENOTCONN; | 2020 errno = ENOTCONN; |
1931 return -1; | 2021 return -1; |
1932 } | 2022 } |
1933 | 2023 |
1934 a.uin = gg_fix32(uin); | 2024 a.uin = gg_fix32(uin); |
1935 a.dunno1 = type; | 2025 a.dunno1 = type; |
1936 | 2026 |
1937 return gg_send_packet(sess, GG_ADD_NOTIFY, &a, sizeof(a), NULL); | 2027 return gg_send_packet(sess, GG_ADD_NOTIFY, &a, sizeof(a), NULL); |
1938 } | 2028 } |
1939 | 2029 |
1940 /* | 2030 /** |
1941 * gg_add_notify() | 2031 * Dodaje kontakt. |
1942 * | 2032 * |
1943 * dodaje do listy kontakt體 dany numer w trakcie po潮czenia. | 2033 * Funkcja jest odpowiednikiem \c gg_add_notify_ex(), gdzie rodzaj wszystkich |
1944 * | 2034 * kontakt贸w to \c GG_USER_NORMAL. |
1945 * - sess - opis sesji | 2035 * |
1946 * - uin - numer | 2036 * \param sess Struktura sesji |
1947 * | 2037 * \param uin Numer kontaktu |
1948 * 0, -1. | 2038 * |
2039 * \return 0 je艣li si臋 powiod艂o, -1 w przypadku b艂臋du | |
2040 * | |
2041 * \ingroup contacts | |
1949 */ | 2042 */ |
1950 int gg_add_notify(struct gg_session *sess, uin_t uin) | 2043 int gg_add_notify(struct gg_session *sess, uin_t uin) |
1951 { | 2044 { |
1952 return gg_add_notify_ex(sess, uin, GG_USER_NORMAL); | 2045 return gg_add_notify_ex(sess, uin, GG_USER_NORMAL); |
1953 } | 2046 } |
1954 | 2047 |
1955 /* | 2048 /** |
1956 * gg_remove_notify_ex() | 2049 * Usuwa kontakt. |
1957 * | 2050 * |
1958 * usuwa z listy kontakt體 w trakcie po潮czenia. | 2051 * Usuwa z listy kontakt贸w dany numer w trakcie po艂膮czenia. |
1959 * usuwanemu u縴tkownikowi okre秎amy jego typ (patrz protocol.html) | 2052 * |
1960 * | 2053 * \param sess Struktura sesji |
1961 * - sess - opis sesji | 2054 * \param uin Numer kontaktu |
1962 * - uin - numer | 2055 * \param type Rodzaj kontaktu |
1963 * - type - typ | 2056 * |
1964 * | 2057 * \return 0 je艣li si臋 powiod艂o, -1 w przypadku b艂臋du |
1965 * 0, -1. | 2058 * |
2059 * \ingroup contacts | |
1966 */ | 2060 */ |
1967 int gg_remove_notify_ex(struct gg_session *sess, uin_t uin, char type) | 2061 int gg_remove_notify_ex(struct gg_session *sess, uin_t uin, char type) |
1968 { | 2062 { |
1969 struct gg_add_remove a; | 2063 struct gg_add_remove a; |
1970 | 2064 |
1971 gg_debug(GG_DEBUG_FUNCTION, "** gg_remove_notify_ex(%p, %u, %d);\n", sess, uin, type); | 2065 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_remove_notify_ex(%p, %u, %d);\n", sess, uin, type); |
1972 | 2066 |
1973 if (!sess) { | 2067 if (!sess) { |
1974 errno = EFAULT; | 2068 errno = EFAULT; |
1975 return -1; | 2069 return -1; |
1976 } | 2070 } |
1977 | 2071 |
1980 return -1; | 2074 return -1; |
1981 } | 2075 } |
1982 | 2076 |
1983 a.uin = gg_fix32(uin); | 2077 a.uin = gg_fix32(uin); |
1984 a.dunno1 = type; | 2078 a.dunno1 = type; |
1985 | 2079 |
1986 return gg_send_packet(sess, GG_REMOVE_NOTIFY, &a, sizeof(a), NULL); | 2080 return gg_send_packet(sess, GG_REMOVE_NOTIFY, &a, sizeof(a), NULL); |
1987 } | 2081 } |
1988 | 2082 |
1989 /* | 2083 /** |
1990 * gg_remove_notify() | 2084 * Usuwa kontakt. |
1991 * | 2085 * |
1992 * usuwa z listy kontakt體 w trakcie po潮czenia. | 2086 * Funkcja jest odpowiednikiem \c gg_add_notify_ex(), gdzie rodzaj wszystkich |
1993 * | 2087 * kontakt贸w to \c GG_USER_NORMAL. |
1994 * - sess - opis sesji | 2088 * |
1995 * - uin - numer | 2089 * \param sess Struktura sesji |
1996 * | 2090 * \param uin Numer kontaktu |
1997 * 0, -1. | 2091 * |
2092 * \return 0 je艣li si臋 powiod艂o, -1 w przypadku b艂臋du | |
2093 * | |
2094 * \ingroup contacts | |
1998 */ | 2095 */ |
1999 int gg_remove_notify(struct gg_session *sess, uin_t uin) | 2096 int gg_remove_notify(struct gg_session *sess, uin_t uin) |
2000 { | 2097 { |
2001 return gg_remove_notify_ex(sess, uin, GG_USER_NORMAL); | 2098 return gg_remove_notify_ex(sess, uin, GG_USER_NORMAL); |
2002 } | 2099 } |
2003 | 2100 |
2004 /* | 2101 /** |
2005 * gg_userlist_request() | 2102 * Wysy艂a do serwera zapytanie dotycz膮ce listy kontakt贸w. |
2006 * | 2103 * |
2007 * wysy砤 勘danie/zapytanie listy kontakt體 na serwerze. | 2104 * Funkcja s艂u偶y do importu lub eksportu listy kontakt贸w do serwera. |
2008 * | 2105 * W odr贸偶nieniu od funkcji \c gg_notify(), ta lista kontakt贸w jest przez |
2009 * - sess - opis sesji | 2106 * serwer jedynie przechowywana i nie ma wp艂ywu na po艂膮czenie. Format |
2010 * - type - rodzaj zapytania/勘dania | 2107 * listy kontakt贸w jest ignorowany przez serwer, ale ze wzgl臋du na |
2011 * - request - tre舵 zapytania/勘dania (mo縠 by NULL) | 2108 * kompatybilno艣膰 z innymi klientami, nale偶y przechowywa膰 dane w tym samym |
2012 * | 2109 * formacie co oryginalny klient Gadu-Gadu. |
2013 * 0, -1 | 2110 * |
2111 * Program nie musi si臋 przejmowa膰 fragmentacj膮 listy kontakt贸w wynikaj膮c膮 | |
2112 * z protoko艂u -- wysy艂a i odbiera kompletn膮 list臋. | |
2113 * | |
2114 * \param sess Struktura sesji | |
2115 * \param type Rodzaj zapytania | |
2116 * \param request Tre艣膰 zapytania (mo偶e by膰 r贸wne NULL) | |
2117 * | |
2118 * \return 0 je艣li si臋 powiod艂o, -1 w przypadku b艂臋du | |
2119 * | |
2120 * \ingroup importexport | |
2014 */ | 2121 */ |
2015 int gg_userlist_request(struct gg_session *sess, char type, const char *request) | 2122 int gg_userlist_request(struct gg_session *sess, char type, const char *request) |
2016 { | 2123 { |
2017 int len; | 2124 int len; |
2018 | 2125 |
2019 if (!sess) { | 2126 if (!sess) { |
2020 errno = EFAULT; | 2127 errno = EFAULT; |
2021 return -1; | 2128 return -1; |
2022 } | 2129 } |
2023 | 2130 |
2024 if (sess->state != GG_STATE_CONNECTED) { | 2131 if (sess->state != GG_STATE_CONNECTED) { |
2025 errno = ENOTCONN; | 2132 errno = ENOTCONN; |
2026 return -1; | 2133 return -1; |
2027 } | 2134 } |
2028 | 2135 |
2029 if (!request) { | 2136 if (!request) { |
2030 sess->userlist_blocks = 1; | 2137 sess->userlist_blocks = 1; |
2031 return gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), NULL); | 2138 return gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), NULL); |
2032 } | 2139 } |
2033 | 2140 |
2034 len = strlen(request); | 2141 len = strlen(request); |
2035 | 2142 |
2036 sess->userlist_blocks = 0; | 2143 sess->userlist_blocks = 0; |
2037 | 2144 |
2038 while (len > 2047) { | 2145 while (len > 2047) { |
2050 | 2157 |
2051 sess->userlist_blocks++; | 2158 sess->userlist_blocks++; |
2052 | 2159 |
2053 return gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), request, len, NULL); | 2160 return gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), request, len, NULL); |
2054 } | 2161 } |
2162 | |
2163 /* @} */ | |
2055 | 2164 |
2056 /* | 2165 /* |
2057 * Local variables: | 2166 * Local variables: |
2058 * c-indentation-style: k&r | 2167 * c-indentation-style: k&r |
2059 * c-basic-offset: 8 | 2168 * c-basic-offset: 8 |