PageRenderTime 36ms CodeModel.GetById 14ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 0ms

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