1
0
mirror of https://github.com/Llewellynvdm/conky.git synced 2024-11-05 21:07:52 +00:00
conky/mldonkey.c

457 lines
8.6 KiB
C

#include "conky.h"
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <fcntl.h>
#include <arpa/inet.h>
int64 buf_to_int(char *buf, int pos, int size);
void int_to_buf(int64 i, char *buf, int pos, int size);
#define BUF16_TO_INT(buf, pos) buf_to_int((buf), (pos), 2)
#define BUF32_TO_INT(buf, pos) buf_to_int((buf), (pos), 4)
#define BUF64_TO_INT(buf, pos) buf_to_int((buf), (pos), 8)
#define INT_TO_BUF16(i, buf, pos) int_to_buf((i), (buf), (pos), 2)
#define INT_TO_BUF32(i, buf, pos) int_to_buf((i), (buf), (pos), 4)
#define INT_TO_BUF64(i, buf, pos) int_to_buf((i), (buf), (pos), 8)
mldonkey_info mlinfo;
mldonkey_config mlconfig;
/* Call this function to update the information about mldonkey.
* Note that the function will not reconnect to mldonkey if the
* pointer to the mldonkey_config has not changed. As it uses static
* data, it cannot be used in a multithreaded env.
* Returns 1 if connected and info filled, 0 if connected but not filled,
* -1 otherwise. */
enum to_gui {
CoreProtocol, /* 0 */
Options_info,
RESERVED2,
DefineSearches,
Result_info,
Search_result,
Search_waiting,
File_info,
File_downloaded,
File_availability,
File_source, /* 10 */
Server_busy,
Server_user,
Server_state,
Server_info,
Client_info,
Client_state,
Client_friend,
Client_file,
Console,
Network_info, /* 20 */
User_info,
Room_info,
Room_message,
Room_add_user,
Client_stats,
Server_info_v2,
MessageFromClient,
ConnectedServers,
DownloadFiles,
DownloadedFiles, /* 30 */
Room_info_v2,
Room_remove_user,
Shared_file_info,
Shared_file_upload,
Shared_file_unshared,
Add_section_option,
Client_stats_v2,
Add_plugin_option,
Client_stats_v3,
File_info_v2, /* 40 */
DownloadFiles_v2,
DownloadedFiles_v2,
File_info_v3,
DownloadFiles_v3,
DownloadedFiles_v3,
File_downloaded_v2,
BadPassword,
Shared_file_info_v2,
Client_stats_v4, /* 49 */
};
#define MLDONKEY_DISCONNECTED 0
#define MLDONKEY_CONNECTING 1
#define MLDONKEY_AUTHENTICATING 2
#define MLDONKEY_CONNECTED 3
#define MAX_MESSAGE_LEN 65000
static int write_pos = 0;
static char write_buf[MAX_MESSAGE_LEN];
static char read_buf[MAX_MESSAGE_LEN];
static int read_pos;
static int mldonkey_sock = -1;
static int mldonkey_state = MLDONKEY_DISCONNECTED;
static mldonkey_config *old_config = NULL;
/* int64 ------------------------------ */
int64 buf_to_int(char *buf, int pos, int size)
{
int i;
int64 res = 0;
for (i = 0; i < size; i++) {
res += (buf[pos + i] & 0xFF) << (8 * i);
}
return res;
}
void int_to_buf(int64 i, char *buf, int pos, int size)
{
int j;
for (j = 0; j < size; j++) {
buf[pos + j] = (i & (-1)) >> (8 * j);
}
}
/* Write operations --------------------- */
void init_message()
{
write_pos = 0;
}
void write_int8(int code)
{
write_buf[write_pos++] = code;
}
void write_opcode(int code)
{
write_buf[write_pos++] = code;
}
void write_int16(int code)
{
INT_TO_BUF16(code, write_buf, write_pos);
write_pos += 2;
}
void write_int32(int code)
{
INT_TO_BUF32(code, write_buf, write_pos);
write_pos += 4;
}
void write_int64(int64 code)
{
INT_TO_BUF64(code, write_buf, write_pos);
write_pos += 8;
}
void write_string(char *str)
{
if (str == NULL) {
write_int16(0);
} else {
int len = strlen(str);
write_int16(len);
memcpy((void *) (write_buf + write_pos), (void *) str,
(size_t) len);
write_pos += len;
}
}
int write_message(char *mtype)
{
char header[4];
INT_TO_BUF32(write_pos, header, 0);
if (4 != write(mldonkey_sock, header, 4) ||
write_pos != write(mldonkey_sock, (void *) write_buf,
(size_t) write_pos)) {
ERR("Error in transmitting %s\n", mtype);
write_pos = 0;
/* Immediatly close the connection */
close(mldonkey_sock);
mldonkey_state = MLDONKEY_DISCONNECTED;
mldonkey_sock = -1;
return -1;
} else {
write_pos = 0;
return 0;
}
}
/* Read operations ----------------------------*/
int read_int8()
{
return read_buf[read_pos++];
}
int read_int16()
{
int i = BUF16_TO_INT(read_buf, read_pos);
read_pos += 2;
return i;
}
int read_int32()
{
int i = BUF32_TO_INT(read_buf, read_pos);
read_pos += 4;
return i;
}
int64 read_int64()
{
int64 i = BUF64_TO_INT(read_buf, read_pos);
read_pos += 8;
return i;
}
char *read_string()
{
char *buf;
int len;
len = BUF16_TO_INT(read_buf, read_pos);
read_pos += 2;
buf = (char *) malloc((size_t) len + 1);
memmove(read_buf + read_pos, buf, len);
buf[len] = 0;
read_pos += len;
return buf;
}
/* protocol impl. ----------------------------- */
void close_sock();
/* This function returns the number of messages read, 0 if it blocks,
-1 on error. */
int cut_messages(int reinit)
{
int nread;
static int toread = 0;
static int pos = 0;
if (reinit) {
toread = 0;
pos = 0;
read_pos = 0;
return 0;
}
while (1) {
if (toread == 0) {
nread =
read(mldonkey_sock, read_buf + pos, 4 - pos);
if (nread <= 0) {
if (errno == EAGAIN) {
return 0;
} else {
close_sock();
pos = 0;
toread = 0;
return -1;
}
}
pos += nread;
if (pos == 4) {
toread = BUF32_TO_INT(read_buf, 0);
pos = 0;
}
} else {
nread =
read(mldonkey_sock, read_buf + pos,
toread - pos);
if (nread <= 0) {
if (errno == EAGAIN)
return 0;
else {
pos = 0;
toread = 0;
close_sock();
return -1;
}
}
pos += nread;
if (pos == toread) {
/* We have one message !!! */
int old_pos = pos;
read_pos = 0;
pos = 0;
toread = 0;
return old_pos;
}
}
}
}
void close_sock()
{
old_config = NULL;
if (mldonkey_sock >= 0)
close(mldonkey_sock);
mldonkey_sock = -1;
mldonkey_state = MLDONKEY_DISCONNECTED;
cut_messages(1);
}
int mldonkey_connect(mldonkey_config * config)
{
if (config != old_config) {
struct sockaddr_in sa;
int retcode;
close_sock();
old_config = config;
/* resolve hostname */
memset(&sa, 0, sizeof(sa));
if (config->mldonkey_hostname == NULL)
config->mldonkey_hostname = "127.0.0.1";
if (config->mldonkey_hostname[0] >= '0' &&
config->mldonkey_hostname[0] <= '9') {
#ifdef HAS_INET_ATON
if (inet_aton
(config->mldonkey_hostname, &sa.sin_addr) == 0)
return -1;
#else
sa.sin_addr.s_addr =
inet_addr(config->mldonkey_hostname);
if (sa.sin_addr.s_addr == (unsigned int) -1)
return -1;
#endif
} else {
struct hostent *hp;
hp = gethostbyname(config->mldonkey_hostname);
if (hp == (struct hostent *) NULL)
return -1;
sa.sin_addr.s_addr =
(unsigned long) hp->h_addr_list[0];
}
sa.sin_port = htons(config->mldonkey_port);
sa.sin_family = AF_INET;
if ((mldonkey_sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
ERR("Opening socket");
close_sock();
return -1;
}
if (connect
(mldonkey_sock, (struct sockaddr *) &sa,
sizeof(sa)) < 0) {
if (errno != EAGAIN && errno != EINTR
&& errno != EINPROGRESS
&& errno != EWOULDBLOCK) {
// ERR("Connection failed");
close_sock();
return -1;
}
}
retcode = fcntl(mldonkey_sock, F_GETFL, 0);
if (retcode == -1 ||
fcntl(mldonkey_sock, F_SETFL,
retcode | O_NONBLOCK) == -1) {
return -1;
}
mldonkey_state = MLDONKEY_CONNECTING;
return 0;
}
return 0;
}
int mldonkey_can_read()
{
return cut_messages(0);
}
int mldonkey_info_message(mldonkey_info * info)
{
int opcode = read_int16();
switch (opcode) {
case CoreProtocol:
init_message();
write_int16(0); /* GUI protocol */
write_int32(10); /* Version 10 ! */
write_message("GuiProtocol");
write_int16(47); /* GUI protocol */
write_int16(1);
write_int32(1);
write_int8(1);
write_message("GuiExtensions");
init_message();
write_int16(5); /* Password */
write_string(old_config->mldonkey_password);
write_message("Password");
break;
case BadPassword:
ERR("Bad Password\n");
close_sock();
break;
case Client_stats:
case Client_stats_v2:
case Client_stats_v3:
ERR("Client stats format too old...\n");
break;
case Client_stats_v4:
mldonkey_state = MLDONKEY_CONNECTED;
info->upload_counter = read_int64();
info->download_counter = read_int64();
info->shared_counter = read_int64();
info->nshared_files = read_int32();
info->tcp_upload_rate = read_int32();
info->tcp_download_rate = read_int32();
info->udp_upload_rate = read_int32();
info->udp_download_rate = read_int32();
info->ndownloading_files = read_int32();
info->ndownloaded_files = read_int32();
break;
}
return 0;
}
int get_mldonkey_status(mldonkey_config * config, mldonkey_info * info)
{
if (mldonkey_connect(config) >= 0) {
while (mldonkey_can_read() > 0) {
mldonkey_info_message(info);
}
}
return mldonkey_state;
}