move conky.1
[monky] / src / mldonkey.c
1 #include "conky.h"
2 #include <string.h>
3 #include <unistd.h>
4 #include <errno.h>
5 #include <netdb.h>
6 #include <fcntl.h>
7 #include <arpa/inet.h>
8
9
10 int64 buf_to_int(char *buf, int pos, int size);
11 void int_to_buf(int64 i, char *buf, int pos, int size);
12
13 #define BUF16_TO_INT(buf, pos) buf_to_int((buf), (pos), 2)
14 #define BUF32_TO_INT(buf, pos) buf_to_int((buf), (pos), 4)
15 #define BUF64_TO_INT(buf, pos) buf_to_int((buf), (pos), 8)
16
17 #define INT_TO_BUF16(i, buf, pos) int_to_buf((i), (buf), (pos), 2)
18 #define INT_TO_BUF32(i, buf, pos) int_to_buf((i), (buf), (pos), 4)
19 #define INT_TO_BUF64(i, buf, pos) int_to_buf((i), (buf), (pos), 8)
20
21 mldonkey_info mlinfo;
22 mldonkey_config mlconfig;
23
24 /* Call this function to update the information about mldonkey.
25  * Note that the function will not reconnect to mldonkey if the
26  * pointer to the mldonkey_config has not changed. As it uses static
27  * data, it cannot be used in a multithreaded env.
28  * Returns 1 if connected and info filled, 0 if connected but not filled,
29  * -1 otherwise. */
30
31 enum to_gui {
32         CoreProtocol,           /* 0 */
33         Options_info,
34         RESERVED2,
35         DefineSearches,
36         Result_info,
37         Search_result,
38         Search_waiting,
39         File_info,
40         File_downloaded,
41         File_availability,
42         File_source,            /* 10 */
43         Server_busy,
44         Server_user,
45         Server_state,
46         Server_info,
47         Client_info,
48         Client_state,
49         Client_friend,
50         Client_file,
51         Console,
52         Network_info,           /* 20 */
53         User_info,
54         Room_info,
55         Room_message,
56         Room_add_user,
57         Client_stats,
58         Server_info_v2,
59         MessageFromClient,
60         ConnectedServers,
61         DownloadFiles,
62         DownloadedFiles,        /* 30 */
63         Room_info_v2,
64         Room_remove_user,
65         Shared_file_info,
66         Shared_file_upload,
67         Shared_file_unshared,
68         Add_section_option,
69         Client_stats_v2,
70         Add_plugin_option,
71         Client_stats_v3,
72         File_info_v2,           /* 40 */
73         DownloadFiles_v2,
74         DownloadedFiles_v2,
75         File_info_v3,
76         DownloadFiles_v3,
77         DownloadedFiles_v3,
78         File_downloaded_v2,
79         BadPassword,
80         Shared_file_info_v2,
81         Client_stats_v4,        /* 49 */
82 };
83
84 #define MLDONKEY_DISCONNECTED   0
85 #define MLDONKEY_CONNECTING     1
86 #define MLDONKEY_AUTHENTICATING 2
87 #define MLDONKEY_CONNECTED      3
88
89 #define MAX_MESSAGE_LEN 65000
90 static int write_pos = 0;
91 static char write_buf[MAX_MESSAGE_LEN];
92 static char read_buf[MAX_MESSAGE_LEN];
93 static int read_pos;
94 static int mldonkey_sock = -1;
95 static int mldonkey_state = MLDONKEY_DISCONNECTED;
96 static mldonkey_config *old_config = NULL;
97
98 /* int64 ------------------------------ */
99
100 int64 buf_to_int(char *buf, int pos, int size)
101 {
102         int i;
103         int64 res = 0;
104
105         for (i = 0; i < size; i++) {
106                 res += (buf[pos + i] & 0xFF) << (8 * i);
107         }
108         return res;
109 }
110
111 void int_to_buf(int64 i, char *buf, int pos, int size)
112 {
113         int j;
114
115         for (j = 0; j < size; j++) {
116                 buf[pos + j] = (i & (-1)) >> (8 * j);
117         }
118 }
119
120 /* Write operations --------------------- */
121
122 void init_message()
123 {
124         write_pos = 0;
125 }
126
127 void write_int8(int code)
128 {
129         write_buf[write_pos++] = code;
130 }
131
132 void write_opcode(int code)
133 {
134         write_buf[write_pos++] = code;
135 }
136
137 void write_int16(int code)
138 {
139         INT_TO_BUF16(code, write_buf, write_pos);
140         write_pos += 2;
141 }
142
143 void write_int32(int code)
144 {
145         INT_TO_BUF32(code, write_buf, write_pos);
146         write_pos += 4;
147 }
148
149 void write_int64(int64 code)
150 {
151         INT_TO_BUF64(code, write_buf, write_pos);
152         write_pos += 8;
153 }
154
155 void write_string(char *str)
156 {
157         if (str == NULL) {
158                 write_int16(0);
159         } else {
160                 int len = strlen(str);
161                 write_int16(len);
162                 memcpy((void *) (write_buf + write_pos), (void *) str,
163                        (size_t) len);
164                 write_pos += len;
165         }
166 }
167
168
169 int write_message(char *mtype)
170 {
171         char header[4];
172
173         INT_TO_BUF32(write_pos, header, 0);
174         if (4 != write(mldonkey_sock, header, 4) ||
175             write_pos != write(mldonkey_sock, (void *) write_buf,
176                                (size_t) write_pos)) {
177                 ERR("Error in transmitting %s\n", mtype);
178                 write_pos = 0;
179
180                 /* Immediatly close the connection */
181                 close(mldonkey_sock);
182                 mldonkey_state = MLDONKEY_DISCONNECTED;
183                 mldonkey_sock = -1;
184                 return -1;
185         } else {
186                 write_pos = 0;
187                 return 0;
188         }
189 }
190
191
192 /* Read operations ----------------------------*/
193
194 int read_int8()
195 {
196         return read_buf[read_pos++];
197 }
198
199 int read_int16()
200 {
201         int i = BUF16_TO_INT(read_buf, read_pos);
202         read_pos += 2;
203         return i;
204 }
205
206 int read_int32()
207 {
208         int i = BUF32_TO_INT(read_buf, read_pos);
209         read_pos += 4;
210         return i;
211 }
212
213 int64 read_int64()
214 {
215         int64 i = BUF64_TO_INT(read_buf, read_pos);
216         read_pos += 8;
217         return i;
218 }
219
220 char *read_string()
221 {
222         char *buf;
223         int len;
224
225         len = BUF16_TO_INT(read_buf, read_pos);
226         read_pos += 2;
227
228         buf = (char *) malloc((size_t) len + 1);
229         memmove(read_buf + read_pos, buf, len);
230         buf[len] = 0;
231         read_pos += len;
232
233         return buf;
234 }
235
236 /* protocol impl. ----------------------------- */
237
238 void close_sock();
239
240 /* This function returns the number of messages read, 0 if it blocks,
241 -1 on error. */
242 int cut_messages(int reinit)
243 {
244         int nread;
245         static int toread = 0;
246         static int pos = 0;
247
248         if (reinit) {
249                 toread = 0;
250                 pos = 0;
251                 read_pos = 0;
252                 return 0;
253         }
254
255         while (1) {
256                 if (toread == 0) {
257                         nread =
258                             read(mldonkey_sock, read_buf + pos, 4 - pos);
259                         if (nread <= 0) {
260                                 if (errno == EAGAIN) {
261                                         return 0;
262                                 } else {
263                                         close_sock();
264                                         pos = 0;
265                                         toread = 0;
266                                         return -1;
267                                 }
268                         }
269                         pos += nread;
270                         if (pos == 4) {
271                                 toread = BUF32_TO_INT(read_buf, 0);
272                                 pos = 0;
273                         }
274                 } else {
275                         nread =
276                             read(mldonkey_sock, read_buf + pos,
277                                  toread - pos);
278                         if (nread <= 0) {
279                                 if (errno == EAGAIN)
280                                         return 0;
281                                 else {
282                                         pos = 0;
283                                         toread = 0;
284                                         close_sock();
285                                         return -1;
286                                 }
287                         }
288                         pos += nread;
289                         if (pos == toread) {
290                                 /* We have one message !!! */
291                                 int old_pos = pos;
292                                 read_pos = 0;
293                                 pos = 0;
294                                 toread = 0;
295
296                                 return old_pos;
297                         }
298                 }
299         }
300 }
301
302 void close_sock()
303 {
304         old_config = NULL;
305         if (mldonkey_sock >= 0)
306                 close(mldonkey_sock);
307         mldonkey_sock = -1;
308         mldonkey_state = MLDONKEY_DISCONNECTED;
309         cut_messages(1);
310 }
311
312 int mldonkey_connect(mldonkey_config * config)
313 {
314         if (config != old_config) {
315                 struct sockaddr_in sa;
316                 int retcode;
317                 close_sock();
318
319
320                 old_config = config;
321                 /* resolve hostname */
322                 memset(&sa, 0, sizeof(sa));
323
324                 if (config->mldonkey_hostname == NULL)
325                         config->mldonkey_hostname = "127.0.0.1";
326                 if (config->mldonkey_hostname[0] >= '0' &&
327                     config->mldonkey_hostname[0] <= '9') {
328 #ifdef HAS_INET_ATON
329                         if (inet_aton
330                             (config->mldonkey_hostname, &sa.sin_addr) == 0)
331                                 return -1;
332 #else
333
334                         sa.sin_addr.s_addr =
335                             inet_addr(config->mldonkey_hostname);
336                         if (sa.sin_addr.s_addr == (unsigned int) -1)
337                                 return -1;
338 #endif
339
340                 } else {
341                         struct hostent *hp;
342                         hp = gethostbyname(config->mldonkey_hostname);
343                         if (hp == (struct hostent *) NULL)
344                                 return -1;
345                         sa.sin_addr.s_addr =
346                             (unsigned long) hp->h_addr_list[0];
347                 }
348
349                 sa.sin_port = htons(config->mldonkey_port);
350                 sa.sin_family = AF_INET;
351
352                 if ((mldonkey_sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
353                         ERR("Opening socket");
354                         close_sock();
355                         return -1;
356                 }
357
358                 if (connect
359                     (mldonkey_sock, (struct sockaddr *) &sa,
360                      sizeof(sa)) < 0) {
361                         if (errno != EAGAIN && errno != EINTR
362                             && errno != EINPROGRESS
363                             && errno != EWOULDBLOCK) {
364 //        ERR("Connection failed");
365                                 close_sock();
366                                 return -1;
367                         }
368                 }
369
370                 retcode = fcntl(mldonkey_sock, F_GETFL, 0);
371                 if (retcode == -1 ||
372                     fcntl(mldonkey_sock, F_SETFL,
373                           retcode | O_NONBLOCK) == -1) {
374                         return -1;
375                 }
376
377
378                 mldonkey_state = MLDONKEY_CONNECTING;
379                 return 0;
380         }
381
382         return 0;
383 }
384
385 int mldonkey_can_read()
386 {
387         return cut_messages(0);
388 }
389
390 int mldonkey_info_message(mldonkey_info * info)
391 {
392         int opcode = read_int16();
393
394         switch (opcode) {
395
396         case CoreProtocol:
397                 init_message();
398
399                 write_int16(0); /* GUI protocol */
400                 write_int32(10);        /* Version 10 ! */
401                 write_message("GuiProtocol");
402
403                 write_int16(47);        /* GUI protocol */
404
405                 write_int16(1);
406                 write_int32(1);
407                 write_int8(1);
408                 write_message("GuiExtensions");
409
410                 init_message();
411                 write_int16(5); /* Password */
412                 write_string(old_config->mldonkey_password);
413                 write_message("Password");
414
415                 break;
416
417         case BadPassword:
418                 ERR("Bad Password\n");
419                 close_sock();
420                 break;
421
422         case Client_stats:
423         case Client_stats_v2:
424         case Client_stats_v3:
425                 ERR("Client stats format too old...\n");
426                 break;
427
428         case Client_stats_v4:
429                 mldonkey_state = MLDONKEY_CONNECTED;
430
431                 info->upload_counter = read_int64();
432                 info->download_counter = read_int64();
433                 info->shared_counter = read_int64();
434                 info->nshared_files = read_int32();
435                 info->tcp_upload_rate = read_int32();
436                 info->tcp_download_rate = read_int32();
437                 info->udp_upload_rate = read_int32();
438                 info->udp_download_rate = read_int32();
439                 info->ndownloading_files = read_int32();
440                 info->ndownloaded_files = read_int32();
441
442                 break;
443         }
444
445         return 0;
446 }
447
448 int get_mldonkey_status(mldonkey_config * config, mldonkey_info * info)
449 {
450         if (mldonkey_connect(config) >= 0) {
451                 while (mldonkey_can_read() > 0) {
452                         mldonkey_info_message(info);
453                 }
454         }
455         return mldonkey_state;
456 }