diff --git a/src/libmra.c b/src/libmra.c index 1702e2e..716a17c 100644 --- a/src/libmra.c +++ b/src/libmra.c @@ -287,6 +287,9 @@ void mra_hello_cb(gpointer data) purple_connection_update_progress(mmp->gc, _("Connecting"), 3, 3); mra_net_send_auth(mmp, username, password, status); + + const char *device_id = purple_account_get_string(mmp->acct, "dev_id", ""); + mra_net_send_device_id(mmp, device_id); } /************************************************************************************************** @@ -1005,6 +1008,56 @@ void mra_get_anketa(PurpleConnection *gc, const char *who) mra_net_send_anketa_info(mmp, who); } +/************************************************************************************************** + Check && Generate device id +**************************************************************************************************/ +const char* mra_generate_device_id() +{ +#define MRA_UUID_LEN 125 + static char buf[MRA_UUID_LEN]; + int fd = open("/proc/sys/kernel/random/uuid", O_RDONLY); + if (fd == -1) + { + purple_debug_info("mra", "%s failed open uuid file: %s", __func__, strerror(errno)); + return NULL; + } + + ssize_t len = 0; + ssize_t r = 0; + while (r = read(fd, buf + len, sizeof(buf) - len)) + { + if (r == -1) + { + purple_debug_info("mra", "%s failed read uuid file: %s", __func__, strerror(errno)); + return NULL; + } + + len += r; + } + + buf[len - 1] = '\0'; // last symbol is \n - not needed + return buf; +} + +void mra_check_device_id(PurpleAccount *acct) +{ + const char* device_id = purple_account_get_string(acct, "dev_id", ""); + if (device_id[0] != '\0') + { + purple_debug_info("mra", "%s device id %s", __func__, device_id); + return; + } + + device_id = mra_generate_device_id(); + if (!device_id) + { + purple_debug_error("mra", "%s Failed to generate device id, will continue without it!", __func__); + return; + } + + purple_account_set_string(acct, "dev_id", device_id); +} + /************************************************************************************************** Connect to server **************************************************************************************************/ @@ -1051,6 +1104,8 @@ void mra_login(PurpleAccount *acct) server = g_strdup(purple_account_get_string(acct, "host", MRA_HOST)); port = purple_account_get_int(acct, "port", MRA_PORT); + mra_check_device_id(acct); + /* // return error if username is invalid if (!mra_email_is_valid(username)) { @@ -1532,6 +1587,10 @@ static void plugin_init(PurplePlugin *plugin) // user defined variable: port to connect (2041) option = purple_account_option_int_new(_("Port"), "port", MRA_PORT); prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option); + +// auto generated device id + option = purple_account_option_string_new(_("Device ID"), "dev_id", ""); + prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option); } /************************************************************************************************** diff --git a/src/libmra.h b/src/libmra.h index fdd0615..6b445ba 100644 --- a/src/libmra.h +++ b/src/libmra.h @@ -37,6 +37,7 @@ #include #include +#include #include #include #include diff --git a/src/mra_net.c b/src/mra_net.c index 45205c2..30ae4af 100644 --- a/src/mra_net.c +++ b/src/mra_net.c @@ -341,6 +341,34 @@ gboolean mra_net_send_auth(mra_serv_conn *mmp, const char *username, const char return ret; } +/************************************************************************************************** + Send 'capabilities: device id' packet +**************************************************************************************************/ + +gboolean mra_net_send_device_id(mra_serv_conn *mmp, const char* device_id) +{ + purple_debug_info("mra", "== %s - %s ==\n", __func__, device_id); + + mrim_packet_header_t head; + char *dev_id_lps = mra_net_mklps(device_id); + uint32_t tag = MRIM_CAPABILITY_DEVICE_ID; + uint32_t tlv_count = 1; + + gboolean ret = FALSE; + + mra_net_fill_cs_header(&head, mmp->seq++, MRIM_CS_CAPABILITIES, LPSSIZE(dev_id_lps) + sizeof(tag)+sizeof(tlv_count)); + mra_net_send(mmp, &head, sizeof(head)); + mra_net_send(mmp, &tlv_count, sizeof(tlv_count)); + mra_net_send(mmp, &tag, sizeof(tag)); + mra_net_send(mmp, dev_id_lps, LPSSIZE(dev_id_lps)); + + ret = mra_net_send_flush(mmp); + + g_free(dev_id_lps); + + return ret; +} + /************************************************************************************************** Send 'receive ack' packet **************************************************************************************************/ diff --git a/src/mra_net.h b/src/mra_net.h index 5f639fb..572eebf 100644 --- a/src/mra_net.h +++ b/src/mra_net.h @@ -89,6 +89,7 @@ gboolean mra_net_ping_timeout_cb(mra_serv_conn *); gboolean mra_net_send_ping(mra_serv_conn *); gboolean mra_net_send_hello(mra_serv_conn *); gboolean mra_net_send_auth(mra_serv_conn *, const char *, const char *, uint32_t); +gboolean mra_net_send_device_id(mra_serv_conn *, const char*); gboolean mra_net_send_receive_ack(mra_serv_conn *, char *, uint32_t); gboolean mra_net_send_message(mra_serv_conn *, const char *, const char *, uint32_t); gboolean mra_net_send_typing(mra_serv_conn *, const char *); diff --git a/src/proto.h b/src/proto.h index 7494eea..bd20fab 100644 --- a/src/proto.h +++ b/src/proto.h @@ -234,6 +234,18 @@ typedef struct _mrim_packet_header_t { //+ statistic packet data: // LPS client description //max 256 +#define MRIM_CS_CAPABILITIES 0x1090 // C -> S +// DWORD capabilities_quantity +// TLV settings[] + #define MRIM_CAPABILITY_ONLINE_ALERTS 0 + #define MRIM_CAPABILITY_OFFLINE_ALERTS 1 + #define MRIM_CAPABILITY_WEBRTC 2 + #define MRIM_CAPABILITY_WEBRTC_BUSY 3 + #define MRIM_CAPABILITY_ARCH 4 + #define MRIM_CAPABILITY_NORTF 5 + #define MRIM_CAPABILITY_DEVICE_ID 6 + #define MRIM_CAPABILITY_ARCH_STATES 41 + typedef struct mrim_connection_params_t { unsigned long ping_period; } mrim_connection_params_t;