initial commit
[mirrors/ArchLinux-Packages.git] / pidgin-qip-decoder / qip-decoder.c
CommitLineData
209feeb0
H
1/*\r
2 Copyright (C) 2008 Viktor Michna\r
3 \r
4 Version 1.3\r
5\r
6 This program is free software; you can redistribute it and/or modify\r
7 it under the terms of the GNU Lesser General Public License as published by\r
8 the Free Software Foundation; either version 2.1 of the License, or\r
9 (at your option) any later version.\r
10\r
11 This program is distributed in the hope that it will be useful,\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
14 GNU Lesser General Public License for more details.\r
15\r
16 You should have received a copy of the GNU Lesser General Public License\r
17 along with this program; if not, write to the Free Software\r
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
19*/\r
20\r
21\r
22#define PURPLE_PLUGINS\r
23\r
24#include <glib.h>\r
25\r
26/* This will prevent compiler errors in some instances and is better explained in the\r
27 * how-to documents on the wiki */\r
28#ifndef G_GNUC_NULL_TERMINATED\r
29# if __GNUC__ >= 4\r
30# define G_GNUC_NULL_TERMINATED __attribute__((__sentinel__))\r
31# else\r
32# define G_GNUC_NULL_TERMINATED\r
33# endif\r
34#endif\r
35\r
36#include "notify.h"\r
37#include "plugin.h"\r
38#include "version.h"\r
39\r
40#include <unistd.h>\r
41#include <string.h>\r
42\r
43#include <stdio.h>\r
44\r
45#include <sys/types.h>\r
46\r
47#ifdef _WIN32\r
48#include <windows.h>\r
49#endif\r
50\r
51#ifndef _WIN32\r
52// Central European languages that use Latin script\r
53static char* win1250_locales = {\r
54 "ro,sl,hu,sk,pl,sq,sr,hr,cs"\r
55};\r
56// Cyrillic alphabets\r
57static char* win1251_locales = {\r
58 //"mn,mk,uz,uk,az,tt,kk,be,ky,bg,sr,ru"\r
59 "mn,mk,uk,tt,kk,be,ky,bg,ru" // uz,az,sr - cyrillic disabled\r
60};\r
61// Western languages\r
62static char* win1252_locales = {\r
63 "en,fr,nl,gl,de,uq,fi,fo,ca,da,es,af,is,id,it,nn,pt,nb,ms"\r
64};\r
65// Greek\r
66static char* win1253_locales = {\r
67 "el"\r
68};\r
69// Turkish\r
70static char* win1254_locales = {\r
71 "uz,az,tr"\r
72};\r
73// Hebrew\r
74static char* win1255_locales = {\r
75 "he"\r
76};\r
77// Arabic\r
78static char* win1256_locales = {\r
79 "ar,fa,ur"\r
80};\r
81// Baltic languages\r
82static char* win1257_locales = {\r
83 "et,lv,lt"\r
84};\r
85// Vietnamese\r
86static char* win1258_locales = {\r
87 "vi"\r
88};\r
89#endif\r
90\r
91static unsigned short win1250_table[] = {\r
92 0x20AC, 0xFFFD, 0x201A, 0xFFFD, 0x201E, 0x2026, 0x2020, 0x2021, 0xFFFD, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179,\r
93 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0xFFFD, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A,\r
94 0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B,\r
95 0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C,\r
96 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,\r
97 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,\r
98 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,\r
99 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9\r
100};\r
101\r
102static unsigned short win1251_table[] = {\r
103 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021, 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F,\r
104 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0xFFFD, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F,\r
105 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7, 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,\r
106 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7, 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457,\r
107 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,\r
108 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,\r
109 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,\r
110 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F\r
111};\r
112\r
113static unsigned short win1252_table[] = {\r
114 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0xFFFD, 0x017D, 0xFFFD,\r
115 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0xFFFD, 0x017E, 0x0178,\r
116 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,\r
117 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,\r
118 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,\r
119 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,\r
120 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,\r
121 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF\r
122};\r
123\r
124static unsigned short win1253_table[] = {\r
125 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0xFFFD, 0x2030, 0xFFFD, 0x2039, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,\r
126 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0xFFFD, 0x2122, 0xFFFD, 0x203A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,\r
127 0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0xFFFD, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015,\r
128 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7, 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F,\r
129 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,\r
130 0x03A0, 0x03A1, 0xFFFD, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,\r
131 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,\r
132 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0xFFFD\r
133};\r
134\r
135static unsigned short win1254_table[] = {\r
136 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0xFFFD, 0xFFFD, 0xFFFD,\r
137 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0xFFFD, 0xFFFD, 0x0178,\r
138 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,\r
139 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,\r
140 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,\r
141 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF,\r
142 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,\r
143 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF\r
144};\r
145\r
146static unsigned short win1255_table[] = {\r
147 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, 0x2030, 0xFFFD, 0x2039, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,\r
148 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC, 0x2122, 0xFFFD, 0x203A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,\r
149 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AA, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,\r
150 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,\r
151 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, 0x05B8, 0x05B9, 0xFFFD, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF,\r
152 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3, 0x05F4, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,\r
153 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,\r
154 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0xFFFD, 0xFFFD, 0x200E, 0x200F, 0xFFFD\r
155};\r
156\r
157static unsigned short win1256_table[] = {\r
158 0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688,\r
159 0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA,\r
160 0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,\r
161 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F,\r
162 0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,\r
163 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7, 0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0641, 0x0642, 0x0643,\r
164 0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF,\r
165 0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7, 0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2\r
166};\r
167\r
168static unsigned short win1257_table[] = {\r
169 0x20AC, 0xFFFD, 0x201A, 0xFFFD, 0x201E, 0x2026, 0x2020, 0x2021, 0xFFFD, 0x2030, 0xFFFD, 0x2039, 0xFFFD, 0x00A8, 0x02C7, 0x00B8,\r
170 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0xFFFD, 0x2122, 0xFFFD, 0x203A, 0xFFFD, 0x00AF, 0x02DB, 0xFFFD,\r
171 0x00A0, 0xFFFD, 0x00A2, 0x00A3, 0x00A4, 0xFFFD, 0x00A6, 0x00A7, 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6,\r
172 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6,\r
173 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B,\r
174 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF,\r
175 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C,\r
176 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9\r
177};\r
178\r
179static unsigned short win1258_table[] = {\r
180 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, 0x2030, 0xFFFD, 0x2039, 0x0152, 0xFFFD, 0xFFFD, 0xFFFD,\r
181 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC, 0x2122, 0xFFFD, 0x203A, 0x0153, 0xFFFD, 0xFFFD, 0x0178,\r
182 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,\r
183 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,\r
184 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x0300, 0x00CD, 0x00CE, 0x00CF,\r
185 0x0110, 0x00D1, 0x0309, 0x00D3, 0x00D4, 0x01A0, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x01AF, 0x0303, 0x00DF,\r
186 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0301, 0x00ED, 0x00EE, 0x00EF,\r
187 0x0111, 0x00F1, 0x0323, 0x00F3, 0x00F4, 0x01A1, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x01B0, 0x20AB, 0x00FF\r
188};\r
189\r
190static unsigned short* win125x_tables[] = {\r
191 win1250_table, win1251_table, win1252_table, win1253_table,\r
192 win1254_table, win1255_table, win1256_table, win1257_table,\r
193 win1258_table\r
194};\r
195\r
196#define CODEPAGE_MIN 1250\r
197#define CODEPAGE_MAX 1258\r
198#define CODEPAGE_TABLE(cp) (((CODEPAGE_MIN<=(cp)) && ((cp)<=CODEPAGE_MAX)) ? win125x_tables[(cp)-CODEPAGE_MIN] : NULL)\r
199\r
200// default encoding table for nonspecified UINs or NULL to disable\r
201static unsigned short* encoding_table;\r
202// mapping UIN => encoding table\r
203static GHashTable* qip_codepages;\r
204\r
205\r
206#ifndef _WIN32\r
207static unsigned int GetACP() {\r
208 char* locale;\r
209 char lang[3];\r
210 //\r
211 locale = getenv("LANG");\r
212 if (!locale) return 0;\r
213 if (strlen(locale)<2) return 0;\r
214 //\r
215 lang[0] = locale[0];\r
216 lang[1] = locale[1];\r
217 lang[2] = 0;\r
218 //\r
219 if (strstr(win1250_locales,lang)) {\r
220 return 1250;\r
221 } else if (strstr(win1251_locales,lang)) {\r
222 return 1251;\r
223 } else if (strstr(win1252_locales,lang)) {\r
224 return 1252;\r
225 } else if (strstr(win1253_locales,lang)) {\r
226 return 1253;\r
227 } else if (strstr(win1254_locales,lang)) {\r
228 return 1254;\r
229 } else if (strstr(win1255_locales,lang)) {\r
230 return 1255;\r
231 } else if (strstr(win1256_locales,lang)) {\r
232 return 1256;\r
233 } else if (strstr(win1257_locales,lang)) {\r
234 return 1257;\r
235 } else if (strstr(win1258_locales,lang)) {\r
236 return 1258;\r
237 } else {\r
238 return 0;\r
239 }\r
240}\r
241#endif\r
242\r
243static int HexValue(char c) {\r
244 if (c>='0' && c<='9') {\r
245 return c-'0';\r
246 } else if (c>='A' && c<='F') {\r
247 return c-('A'-0x0A);\r
248 } else if (c>='a' && c<='f') {\r
249 return c-('a'-0x0A);\r
250 } else {\r
251 return -1;\r
252 }\r
253}\r
254\r
255static int UTF8Char(char* str, unsigned short code) {\r
256 if (code<=0x7F) {\r
257 if (str) {\r
258 str[0] = code;\r
259 }\r
260 return 1;\r
261 } else if (code<=0x7FF) {\r
262 if (str) {\r
263 str[0] = 0xC0 | (code >> 6);\r
264 str[1] = 0x80 | (code & 0x3F);\r
265 }\r
266 return 2;\r
267 } else {\r
268 if (str) {\r
269 str[0] = 0xE0 | (code >> 12);\r
270 str[1] = 0x80 | ((code >> 6) & 0x3F);\r
271 str[2] = 0x80 | (code & 0x3F);\r
272 }\r
273 return 3;\r
274 }\r
275}\r
276\r
277static unsigned short* get_table_by_uin(char* uin) {\r
278 char* key;\r
279 unsigned short* table = encoding_table;\r
280 if (uin && qip_codepages) {\r
281 if (!g_hash_table_lookup_extended(qip_codepages, uin, (gpointer *)&key, (gpointer *)&table)) {\r
282 table = encoding_table;\r
283 }\r
284 }\r
285 return table;\r
286}\r
287\r
288static gboolean receiving_im_msg_cb(PurpleAccount *account, char **sender, char **buffer, PurpleConversation *conv, PurpleMessageFlags *flags, void *data) {\r
289\r
290 char c;\r
291 int hex_digit;\r
292 char* str;\r
293 int remaining;\r
294 int length;\r
295 int new_length;\r
296 int position;\r
297 int encoded_size;\r
298 int decoded_size;\r
299 unsigned short char_code; // ansi/unicode character\r
300 unsigned short* table;\r
301\r
302 // return immediately, if not the ICQ protocol\r
303 if (strcmp("prpl-icq",purple_account_get_protocol_id(account))!=0) return FALSE;\r
304\r
305 // return if fix is disabled for the UIN\r
306 table = get_table_by_uin(*sender);\r
307 if (!table) return FALSE;\r
308\r
309\r
310 // The following conversion is made so we almost never need message buffer\r
311 // memory reallocation.\r
312\r
313 str = *buffer; // position in the message\r
314 length = strlen(str);\r
315 remaining = length; // remaining chars to iterate\r
316 position = 0;\r
317\r
318 // pro each character in the message\r
319 for (; remaining>0; str++, position++, remaining--) {\r
320 c=*str;\r
321 if (c==0) break;\r
322\r
323 // Check, if there's a broken character at the current position.\r
324 // If so, we'll compute the ansi code (0x80-0xFF) in char_code.\r
325 //\r
326 // The QIP uses WINDOWS-1251 character encoding, but not complete.\r
327 // It seems, russian authors of QIP implemented only support for\r
328 // russian characters, but not for other languages that are using\r
329 // WINDOWS-1251 encoding. Maybe, they wanted to avoid the usage of\r
330 // a complete convert table or system unicode functions, so they\r
331 // only used the approximate relationship between unicode cyrillic\r
332 // codes and windows codes (linear function) and corrected only\r
333 // a few of characters. I managed to determine the technique, so now\r
334 // we can perform the reverse sequence.\r
335 //\r
336 if ((c=='&') && (remaining>=6) && (str[1]=='#') && (str[2]=='x') && (str[5]==';')) {\r
337 // hexa code &#xXX;\r
338 hex_digit = HexValue(str[3]);\r
339 if (hex_digit<0) continue;\r
340 char_code = hex_digit << 4;\r
341 hex_digit = HexValue(str[4]);\r
342 if (hex_digit<0) continue;\r
343 char_code += hex_digit;\r
344 encoded_size = 6;\r
345 } else if ((c==(char)0xC2) && (remaining>=2)) {\r
346 // code 0xC2,0xXX\r
347 char_code = str[1] & 0xFF;\r
348 if (char_code<0x80 || char_code>0xBF) continue;\r
349 encoded_size = 2;\r
350 } else if ((c==(char)0xD0) && (remaining>=2)) {\r
351 // code 0xD0,0xXX\r
352 char_code = str[1] & 0xFF;\r
353 if (char_code == 0x81) {\r
354 char_code = 0xA8;\r
355 } else {\r
356 if (char_code<0x90 || char_code>0xBF) continue;\r
357 char_code += 0x30;\r
358 }\r
359 encoded_size = 2;\r
360 } else if ((c==(char)0xD1) && (remaining>=2)) {\r
361 // code 0xD1,0xXX\r
362 char_code = str[1] & 0xFF;\r
363 if (char_code == 0x91) {\r
364 char_code = 0xB8;\r
365 } else {\r
366 if (char_code<0x80 || char_code>0x8F) continue;\r
367 char_code += 0x70;\r
368 }\r
369 encoded_size = 2;\r
370 } else {\r
371 continue;\r
372 }\r
373\r
374 // convert native character code to unicode character\r
375 if (char_code>=0x80) {\r
376 char_code = table[char_code-0x80];\r
377 }\r
378\r
379 // now we must replace the bad character code with a right one\r
380 decoded_size = UTF8Char(NULL, char_code);\r
381\r
382 // check if there's enough space to replace characters\r
383 if ((decoded_size - encoded_size) > (length - (position + remaining))) {\r
384 // we must realloc the message buffer;\r
385 // compute minimal new buffer size (plus zero term. char)\r
386 new_length = position + remaining + decoded_size - encoded_size + 1;\r
387 // ceil round to multiplier of 256\r
388 new_length = ((new_length + 255) / 256) * 256;\r
389 // realloc\r
390 str = malloc(new_length);\r
391 if (!str) return TRUE;\r
392 // correct size to that without zero term. char\r
393 new_length--;\r
394 // copy message begin\r
395 memcpy(\r
396 str,\r
397 *buffer,\r
398 position\r
399 );\r
400 // copy message end\r
401 memcpy(\r
402 &(str[position+decoded_size]),\r
403 &((*buffer)[position+encoded_size]),\r
404 remaining-encoded_size\r
405 );\r
406 // free old buffer\r
407 free(*buffer);\r
408 *buffer = str;\r
409 str += position;\r
410 //\r
411 length = new_length;\r
412 remaining += (decoded_size-encoded_size);\r
413 encoded_size = decoded_size;\r
414 // zero the added chars\r
415 memset(\r
416 &((*buffer)[position+remaining]),\r
417 0,\r
418 length-(position+remaining)+1\r
419 );\r
420 } else if (decoded_size!=encoded_size) {\r
421 // shift message\r
422 memmove(\r
423 &(str[decoded_size]),\r
424 &(str[encoded_size]),\r
425 remaining-encoded_size\r
426 );\r
427 }\r
428\r
429 // correct the character\r
430 UTF8Char(str, char_code);\r
431 \r
432 // zero the remaining characters\r
433 if (encoded_size>decoded_size) {\r
434 memset(\r
435 &(str[remaining-(encoded_size-decoded_size)]),\r
436 0,\r
437 encoded_size-decoded_size\r
438 );\r
439 }\r
440\r
441 // shift\r
442 position += (decoded_size-1);\r
443 str += (decoded_size-1);\r
444 remaining -= (encoded_size-1);\r
445 \r
446 }\r
447 return FALSE;\r
448\r
449}\r
450\r
451unsigned int str2intdef(const char *str, unsigned int def) {\r
452 unsigned int num;\r
453 if (!str || sscanf(str,"%d",&num)!=1) {\r
454 return def;\r
455 }\r
456 return num;\r
457}\r
458\r
459static gboolean plugin_load(PurplePlugin *plugin) {\r
460\r
461 const char *uin;\r
462 xmlnode *xml,*node;\r
463 unsigned int codepage;\r
464 gboolean enabled;\r
465 gboolean default_enabled;\r
466 unsigned int default_codepage;\r
467\r
468 qip_codepages = NULL;\r
469 default_enabled = TRUE;\r
470 default_codepage = 0;\r
471\r
472 // load codepage configuration\r
473 xml = purple_util_read_xml_from_file("qips.xml","qips.xml");\r
474 if (xml) {\r
475 node = xmlnode_get_child(xml,"default");\r
476 if (node) {\r
477 // default setting for all UINs\r
478 default_enabled = str2intdef(xmlnode_get_attrib(node,"enabled"),default_enabled);\r
479 default_codepage = str2intdef(xmlnode_get_attrib(node,"codepage"),default_codepage);\r
480 }\r
481 }\r
482\r
483 // get default codepage from system\r
484 if (default_codepage<CODEPAGE_MIN || default_codepage>CODEPAGE_MAX) {\r
485 // try to use environment variable 'QIPACP' containing CP number\r
486 default_codepage = str2intdef(getenv("QIPACP"),0);\r
487 if (default_codepage<CODEPAGE_MIN || default_codepage>CODEPAGE_MAX) {\r
488 // now, try to use system ansi code page\r
489 default_codepage = GetACP();\r
490 if (default_codepage<CODEPAGE_MIN || default_codepage>CODEPAGE_MAX) {\r
491 default_codepage = 0;\r
492 default_enabled = FALSE;\r
493 }\r
494 }\r
495 }\r
496\r
497 if (xml) {\r
498 // UIN based codepage setting\r
499 for (node = xmlnode_get_child(xml,"qip"); node; node = xmlnode_get_next_twin(node)) {\r
500 uin = xmlnode_get_attrib(node,"uin");\r
501 if (!uin) continue;\r
502 if (!qip_codepages) qip_codepages = g_hash_table_new(g_str_hash,g_str_equal);\r
503 enabled = str2intdef(xmlnode_get_attrib(node,"enabled"),default_enabled);\r
504 codepage = str2intdef(xmlnode_get_attrib(node,"codepage"),default_codepage);\r
505 //\r
506 if (!enabled || codepage<CODEPAGE_MIN || codepage>CODEPAGE_MAX) codepage = 0;\r
507 //\r
508 g_hash_table_insert(qip_codepages,g_strdup(uin),CODEPAGE_TABLE(codepage));\r
509 }\r
510 xmlnode_free(xml);\r
511 }\r
512\r
513 // finally, assign the unicode table according to the code page\r
514 if (!default_enabled) default_codepage = 0;\r
515 encoding_table = CODEPAGE_TABLE(default_codepage);\r
516\r
517 //\r
518 purple_signal_connect(purple_conversations_get_handle(), "receiving-im-msg", plugin, PURPLE_CALLBACK(receiving_im_msg_cb), NULL);\r
519 return TRUE;\r
520}\r
521\r
522static gboolean dealloc_all(gpointer key, gpointer val, gpointer user_data) {\r
523 g_free(key);\r
524 return (TRUE);\r
525}\r
526\r
527static gboolean plugin_unload(PurplePlugin *plugin) {\r
528 purple_signal_disconnect(purple_conversations_get_handle(), "receiving-im-msg", plugin, PURPLE_CALLBACK(receiving_im_msg_cb));\r
529 //\r
530 if (qip_codepages) {\r
531 g_hash_table_foreach_remove(qip_codepages, dealloc_all, NULL);\r
532 g_hash_table_destroy(qip_codepages);\r
533 qip_codepages = NULL;\r
534 }\r
535 return TRUE;\r
536}\r
537\r
538static PurplePluginInfo info = {\r
539 PURPLE_PLUGIN_MAGIC,\r
540 PURPLE_MAJOR_VERSION,\r
541 PURPLE_MINOR_VERSION,\r
542 PURPLE_PLUGIN_STANDARD,\r
543 NULL,\r
544 0,\r
545 NULL,\r
546 PURPLE_PRIORITY_DEFAULT,\r
547\r
548 "qip-decoder",\r
549 "QIP Decoder",\r
550 "1.3",\r
551\r
552 "QIP Decoder Plugin",\r
553 "Displays diacritic letters from QIP IM correctly.",\r
554 "Viktor Michna (viktor.michna@sedaha.cz)",\r
555 "http://www.sedaha.cz/qip-decoder/",\r
556\r
557 plugin_load,\r
558 plugin_unload,\r
559 NULL,\r
560\r
561 NULL,\r
562 NULL,\r
563 NULL,\r
564 NULL,\r
565 NULL,\r
566 NULL,\r
567 NULL,\r
568 NULL\r
569};\r
570\r
571static void init_plugin(PurplePlugin *plugin) {\r
572\r
573}\r
574\r
575PURPLE_INIT_PLUGIN(qip, init_plugin, info);\r
This page took 0.516371 seconds and 4 git commands to generate.