/package.c

https://code.google.com/ · C · 322 lines · 285 code · 19 blank · 18 comment · 52 complexity · 7001fcb420ad4af64c5e81ae53aece13 MD5 · raw file

  1. /*
  2. * This file is part of mrim-prpl.
  3. *
  4. * mrim-prpl is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * mrim-prpl is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with mrim-prpl. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include "mrim.h"
  18. #include "package.h"
  19. #include <stdarg.h>
  20. MrimPackage *mrim_package_new(guint32 seq, guint32 type) {
  21. MrimPackage *pack = g_new0(MrimPackage, 1);
  22. pack->header = g_new0(mrim_packet_header_t, 1);
  23. pack->header->magic = CS_MAGIC;
  24. pack->header->proto = PROTO_VERSION;
  25. pack->header->seq = seq;
  26. pack->header->msg = type;
  27. return pack;
  28. }
  29. void mrim_package_free(MrimPackage *pack) {
  30. if (pack){
  31. g_free(pack->header);
  32. g_free(pack->data);
  33. g_free(pack);
  34. }
  35. else
  36. purple_debug_error("mrim-prpl", "[%s] pack == NULL\n", __func__);
  37. }
  38. gboolean mrim_package_send(MrimPackage *pack, MrimData *mrim) {
  39. pack->header->dlen = pack->data_size;
  40. gsize ret, size;
  41. if (pack->data) {
  42. size = sizeof(mrim_packet_header_t) + pack->data_size;
  43. gchar *buffer = g_new(gchar, size);
  44. g_memmove(buffer, pack->header, sizeof(mrim_packet_header_t));
  45. g_memmove(buffer + sizeof(mrim_packet_header_t), pack->data, pack->data_size);
  46. ret = send(mrim->fd, buffer, size, 0);
  47. g_free(buffer);
  48. } else {
  49. size = sizeof(mrim_packet_header_t);
  50. ret = send(mrim->fd, pack->header, size, 0);
  51. }
  52. purple_debug_info("mrim-prpl", "[%s] Package sent: type is 0x%x, seq is %i\n", __func__,
  53. pack->header->msg, pack->header->seq);
  54. mrim_package_free(pack);
  55. return (ret >= size);
  56. }
  57. static mrim_packet_header_t *read_header(MrimData *mrim)
  58. {
  59. mrim_packet_header_t *header = g_new0(mrim_packet_header_t, 1);
  60. gsize ret = recv(mrim->fd, header, sizeof(mrim_packet_header_t), 0);
  61. if (ret < sizeof(mrim_packet_header_t)) {
  62. g_free(header);
  63. purple_debug_info("mrim-prpl", "[%s] Package header len is %d instead of %d\n", __func__, ret, sizeof(mrim_packet_header_t));
  64. return NULL;
  65. }
  66. if (header->magic == CS_MAGIC) {
  67. return header;
  68. } else {
  69. purple_debug_info("mrim-prpl", "[%s] Package header MAGIC is 0x%x instead of 0x%x\n", __func__, header->magic, CS_MAGIC);
  70. g_free(header);
  71. return NULL;
  72. }
  73. }
  74. MrimPackage *mrim_package_read(MrimData *mrim) {
  75. ssize_t ret = 0;
  76. if (mrim->inp_package) {
  77. MrimPackage *pack = mrim->inp_package;
  78. gsize size = pack->data_size - pack->cur;
  79. ret = recv(mrim->fd, pack->data + pack->cur, size, 0);
  80. if (ret > 0) {
  81. if (ret < size) {
  82. pack->cur += ret;
  83. return NULL;
  84. } else {
  85. pack->cur = 0;
  86. mrim->inp_package = NULL;
  87. return pack;
  88. }
  89. }
  90. } else {
  91. MrimPackage *pack = g_new0(MrimPackage, 1);
  92. pack->header = read_header(mrim);
  93. if (pack->header == NULL) {
  94. g_free(pack);
  95. return NULL;
  96. }
  97. purple_debug_info("mrim-prpl", "[%s] seq = %u, type = 0x%x len = %u\n", __func__, pack->header->seq, pack->header->msg, pack->header->dlen);
  98. pack->data_size = pack->header->dlen;
  99. pack->data = g_new0(char, pack->data_size);
  100. pack->cur = 0;
  101. if (pack->data_size)
  102. {
  103. ret = recv(mrim->fd, pack->data, pack->data_size, 0);
  104. if ((ret < (pack->data_size)) && (ret > 0)) {
  105. pack->cur += ret;
  106. mrim->inp_package = pack;
  107. return NULL;
  108. }
  109. if (ret == pack->data_size) {
  110. return pack;
  111. }
  112. }
  113. else
  114. return pack;
  115. }
  116. if (ret < 0) {
  117. if (mrim->gc)
  118. purple_connection_error(mrim->gc, _("Read Error!") );
  119. return NULL;
  120. }
  121. if (ret == 0) {
  122. if (mrim->gc)
  123. purple_connection_error(mrim->gc, _("Peer closed connection"));
  124. return NULL;
  125. }
  126. return NULL;
  127. }
  128. /* Package parsing */
  129. gboolean mrim_package_read_raw(MrimPackage *pack, gpointer buffer, gsize size) {
  130. if (pack && pack->data) {
  131. if (pack->cur + size <= pack->data_size) {
  132. g_memmove(buffer, pack->data + pack->cur, size);
  133. pack->cur += size;
  134. return TRUE;
  135. } else {
  136. purple_debug_error("mrim-prpl", "[%s] Insufficient data in the buffer\n", __func__);
  137. return FALSE;
  138. }
  139. } else {
  140. purple_debug_info("mrim-prpl", "[%s] Null buffer!\n", __func__);
  141. return FALSE;
  142. }
  143. }
  144. guint32 mrim_package_read_UL(MrimPackage *pack) {
  145. guint32 result;
  146. if (mrim_package_read_raw(pack, &result, sizeof(result))) {
  147. return result;
  148. } else {
  149. return 0;
  150. }
  151. }
  152. gchar *mrim_package_read_LPSA(MrimPackage *pack) {
  153. gsize str_len = mrim_package_read_UL(pack);
  154. if (str_len) {
  155. gchar *str = g_new(gchar, str_len + 1);
  156. mrim_package_read_raw(pack, str, str_len);
  157. str[str_len] = '\0';
  158. gchar *string = g_convert(str, -1, "UTF8" , "CP1251", NULL, NULL, NULL);
  159. g_free(str);
  160. return string;
  161. } else {
  162. return NULL;
  163. }
  164. }
  165. gchar *mrim_package_read_LPSW(MrimPackage *pack) {
  166. gsize str_len = mrim_package_read_UL(pack);
  167. if (str_len) {
  168. gunichar2 *str = g_new(gunichar2, str_len / sizeof(gunichar2) + 1);
  169. mrim_package_read_raw(pack, str, str_len);
  170. str[str_len / sizeof(gunichar2)] = '\0';
  171. gchar *string = g_utf16_to_utf8(str, -1, NULL, NULL, NULL);
  172. g_free(str);
  173. return string;
  174. } else {
  175. return NULL;
  176. }
  177. }
  178. gchar *mrim_package_read_UIDL(MrimPackage *pack) {
  179. gchar *uidl = g_new(gchar, 8);
  180. mrim_package_read_raw(pack, uidl, 8);
  181. return uidl;
  182. }
  183. gchar *mrim_package_read_LPS(MrimPackage *pack) {
  184. gsize str_len = mrim_package_read_UL(pack);
  185. if (str_len) {
  186. gpointer str = g_new(gchar, str_len);
  187. mrim_package_read_raw(pack, str, str_len);
  188. gboolean valid_utf16 = TRUE;
  189. {
  190. gunichar2 *string = str;
  191. glong i;
  192. for (i = 0; i < (str_len / 2); i++) {
  193. gunichar ch = string[i];
  194. purple_debug_info("mrim-prpl", "[%s] Is char 0x%x defined??\n", __func__, ch);
  195. if ((!g_unichar_isdefined(ch)) || (ch >= 0xE000) && (ch < 0xF900)) {
  196. valid_utf16 = FALSE;
  197. break;
  198. }
  199. }
  200. }
  201. gchar *string;
  202. if (valid_utf16) {
  203. string = g_utf16_to_utf8(str, str_len / 2, NULL, NULL, NULL);
  204. } else {
  205. string = g_convert(str, str_len, "UTF8" , "CP1251", NULL, NULL, NULL);
  206. }
  207. g_free(str);
  208. return string;
  209. } else {
  210. return NULL;
  211. }
  212. }
  213. /* Package creating */
  214. void mrim_package_add_raw(MrimPackage *pack, gchar *data, gsize data_size) {
  215. if (pack) {
  216. if (pack->data) {
  217. pack->data = g_realloc(pack->data, pack->data_size + data_size);
  218. g_memmove(pack->data + pack->data_size, data, data_size);
  219. pack->data_size += data_size;
  220. } else {
  221. pack->data = g_memdup(data, data_size);
  222. pack->data_size = data_size;
  223. }
  224. }
  225. }
  226. void mrim_package_add_UL(MrimPackage *pack, guint32 value) {
  227. mrim_package_add_raw(pack, (gchar*)&value, sizeof(value));
  228. }
  229. void mrim_package_add_LPSA(MrimPackage *pack, gchar *string) {
  230. gsize str_len;
  231. gchar *str = g_convert_with_fallback(string, -1, "CP1251" , "UTF8", NULL, NULL, &str_len, NULL);
  232. if (str) {
  233. mrim_package_add_UL(pack, str_len);
  234. mrim_package_add_raw(pack, str, str_len);
  235. g_free(str);
  236. } else {
  237. mrim_package_add_UL(pack, 0);
  238. }
  239. }
  240. void mrim_package_add_LPSW(MrimPackage *pack, gchar *string) {
  241. glong str_len;
  242. gunichar2 *str = g_utf8_to_utf16(string, -1, NULL, &str_len, NULL);
  243. if (str) {
  244. mrim_package_add_UL(pack, str_len * sizeof(gunichar2));
  245. mrim_package_add_raw(pack, (gchar*)str, str_len * sizeof(gunichar2));
  246. g_free(str);
  247. } else {
  248. mrim_package_add_UL(pack, 0);
  249. }
  250. }
  251. void mrim_package_add_UIDL(MrimPackage *pack, gchar *uidl) {
  252. mrim_package_add_raw(pack, uidl, 8);
  253. }
  254. void mrim_package_add_base64(MrimPackage *pack, gchar *fmt, ...) {
  255. gchar *buffer = NULL;
  256. gsize buffer_size = 0;
  257. va_list ap;
  258. va_start(ap, fmt);
  259. while (*fmt) {
  260. switch (*fmt) {
  261. case 'u':
  262. {
  263. guint32 value = va_arg(ap, guint32);
  264. buffer = g_realloc(buffer, buffer_size + sizeof(guint32));
  265. g_memmove(buffer + buffer_size, &value, sizeof(guint32));
  266. buffer_size += sizeof(guint32);
  267. }
  268. break;
  269. case 's': //CP1251
  270. {
  271. gchar *string = va_arg(ap, gchar*);
  272. gsize str_len = g_utf8_strlen(string, -1);
  273. buffer = g_realloc(buffer, buffer_size + sizeof(guint32) + str_len);
  274. g_memmove(buffer + buffer_size, &str_len, sizeof(guint32));
  275. gchar *str = g_convert_with_fallback(string, -1, "CP1251" , "UTF8", NULL, NULL, NULL, NULL);
  276. g_memmove(buffer + buffer_size + sizeof(guint32), str, str_len);
  277. g_free(str);
  278. buffer_size += sizeof(guint32) + str_len;
  279. }
  280. break;
  281. case 'w': //UTF16
  282. {
  283. gchar *string = va_arg(ap, gchar*);
  284. gsize str_len = g_utf8_strlen(string, -1) * sizeof(gunichar2);
  285. buffer = g_realloc(buffer, buffer_size + sizeof(guint32) + str_len);
  286. g_memmove(buffer + buffer_size, &str_len, sizeof(guint32));
  287. gunichar2 *str = g_utf8_to_utf16(string, -1, NULL, NULL, NULL);
  288. g_memmove(buffer + buffer_size + sizeof(guint32), str, str_len);
  289. g_free(str);
  290. buffer_size += sizeof(guint32) + str_len;
  291. }
  292. break;
  293. }
  294. fmt++;
  295. }
  296. va_end(ap);
  297. gchar *encoded = purple_base64_encode((gchar*)buffer, buffer_size);
  298. guint32 encoded_len = strlen(encoded);
  299. mrim_package_add_UL(pack, encoded_len);
  300. mrim_package_add_raw(pack, encoded, encoded_len);
  301. g_free(encoded);
  302. g_free(buffer);
  303. }