1
0
mirror of https://github.com/Llewellynvdm/conky.git synced 2024-12-26 12:27:52 +00:00
conky/mldonkey.c

433 lines
8.9 KiB
C
Raw Normal View History

#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include "conky.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;
}