2 Copyright (C) 2008 Viktor Michna
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #define PURPLE_PLUGINS
26 /* This will prevent compiler errors in some instances and is better explained in the
27 * how-to documents on the wiki */
28 #ifndef G_GNUC_NULL_TERMINATED
30 # define G_GNUC_NULL_TERMINATED __attribute__((__sentinel__))
32 # define G_GNUC_NULL_TERMINATED
45 #include <sys/types.h>
52 // Central European languages that use Latin script
53 static char* win1250_locales
= {
54 "ro,sl,hu,sk,pl,sq,sr,hr,cs"
57 static char* win1251_locales
= {
58 //"mn,mk,uz,uk,az,tt,kk,be,ky,bg,sr,ru"
59 "mn,mk,uk,tt,kk,be,ky,bg,ru" // uz,az,sr - cyrillic disabled
62 static char* win1252_locales
= {
63 "en,fr,nl,gl,de,uq,fi,fo,ca,da,es,af,is,id,it,nn,pt,nb,ms"
66 static char* win1253_locales
= {
70 static char* win1254_locales
= {
74 static char* win1255_locales
= {
78 static char* win1256_locales
= {
82 static char* win1257_locales
= {
86 static char* win1258_locales
= {
91 static unsigned short win1250_table
[] = {
92 0x20AC, 0xFFFD, 0x201A, 0xFFFD, 0x201E, 0x2026, 0x2020, 0x2021, 0xFFFD, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179,
93 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0xFFFD, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A,
94 0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B,
95 0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C,
96 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
97 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
98 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
99 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9
102 static unsigned short win1251_table
[] = {
103 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021, 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F,
104 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0xFFFD, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F,
105 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7, 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,
106 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7, 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457,
107 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
108 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
109 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
110 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F
113 static unsigned short win1252_table
[] = {
114 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0xFFFD, 0x017D, 0xFFFD,
115 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0xFFFD, 0x017E, 0x0178,
116 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
117 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
118 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
119 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
120 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
121 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
124 static unsigned short win1253_table
[] = {
125 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0xFFFD, 0x2030, 0xFFFD, 0x2039, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
126 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0xFFFD, 0x2122, 0xFFFD, 0x203A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
127 0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0xFFFD, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015,
128 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7, 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F,
129 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
130 0x03A0, 0x03A1, 0xFFFD, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
131 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
132 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0xFFFD
135 static unsigned short win1254_table
[] = {
136 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0xFFFD, 0xFFFD, 0xFFFD,
137 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0xFFFD, 0xFFFD, 0x0178,
138 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
139 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
140 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
141 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF,
142 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
143 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF
146 static unsigned short win1255_table
[] = {
147 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, 0x2030, 0xFFFD, 0x2039, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
148 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC, 0x2122, 0xFFFD, 0x203A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
149 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AA, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
150 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
151 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, 0x05B8, 0x05B9, 0xFFFD, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF,
152 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3, 0x05F4, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
153 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
154 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0xFFFD, 0xFFFD, 0x200E, 0x200F, 0xFFFD
157 static unsigned short win1256_table
[] = {
158 0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688,
159 0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA,
160 0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
161 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F,
162 0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
163 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7, 0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0641, 0x0642, 0x0643,
164 0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF,
165 0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7, 0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2
168 static unsigned short win1257_table
[] = {
169 0x20AC, 0xFFFD, 0x201A, 0xFFFD, 0x201E, 0x2026, 0x2020, 0x2021, 0xFFFD, 0x2030, 0xFFFD, 0x2039, 0xFFFD, 0x00A8, 0x02C7, 0x00B8,
170 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0xFFFD, 0x2122, 0xFFFD, 0x203A, 0xFFFD, 0x00AF, 0x02DB, 0xFFFD,
171 0x00A0, 0xFFFD, 0x00A2, 0x00A3, 0x00A4, 0xFFFD, 0x00A6, 0x00A7, 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6,
172 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6,
173 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B,
174 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF,
175 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C,
176 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9
179 static unsigned short win1258_table
[] = {
180 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, 0x2030, 0xFFFD, 0x2039, 0x0152, 0xFFFD, 0xFFFD, 0xFFFD,
181 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC, 0x2122, 0xFFFD, 0x203A, 0x0153, 0xFFFD, 0xFFFD, 0x0178,
182 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
183 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
184 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x0300, 0x00CD, 0x00CE, 0x00CF,
185 0x0110, 0x00D1, 0x0309, 0x00D3, 0x00D4, 0x01A0, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x01AF, 0x0303, 0x00DF,
186 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0301, 0x00ED, 0x00EE, 0x00EF,
187 0x0111, 0x00F1, 0x0323, 0x00F3, 0x00F4, 0x01A1, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x01B0, 0x20AB, 0x00FF
190 static unsigned short* win125x_tables
[] = {
191 win1250_table
, win1251_table
, win1252_table
, win1253_table
,
192 win1254_table
, win1255_table
, win1256_table
, win1257_table
,
196 #define CODEPAGE_MIN 1250
197 #define CODEPAGE_MAX 1258
198 #define CODEPAGE_TABLE(cp) (((CODEPAGE_MIN<=(cp)) && ((cp)<=CODEPAGE_MAX)) ? win125x_tables[(cp)-CODEPAGE_MIN] : NULL)
200 // default encoding table for nonspecified UINs or NULL to disable
201 static unsigned short* encoding_table
;
202 // mapping UIN => encoding table
203 static GHashTable
* qip_codepages
;
207 static unsigned int GetACP() {
211 locale
= getenv("LANG");
212 if (!locale
) return 0;
213 if (strlen(locale
)<2) return 0;
219 if (strstr(win1250_locales
,lang
)) {
221 } else if (strstr(win1251_locales
,lang
)) {
223 } else if (strstr(win1252_locales
,lang
)) {
225 } else if (strstr(win1253_locales
,lang
)) {
227 } else if (strstr(win1254_locales
,lang
)) {
229 } else if (strstr(win1255_locales
,lang
)) {
231 } else if (strstr(win1256_locales
,lang
)) {
233 } else if (strstr(win1257_locales
,lang
)) {
235 } else if (strstr(win1258_locales
,lang
)) {
243 static int HexValue(char c
) {
244 if (c
>='0' && c
<='9') {
246 } else if (c
>='A' && c
<='F') {
248 } else if (c
>='a' && c
<='f') {
255 static int UTF8Char(char* str
, unsigned short code
) {
261 } else if (code
<=0x7FF) {
263 str
[0] = 0xC0 | (code
>> 6);
264 str
[1] = 0x80 | (code
& 0x3F);
269 str
[0] = 0xE0 | (code
>> 12);
270 str
[1] = 0x80 | ((code
>> 6) & 0x3F);
271 str
[2] = 0x80 | (code
& 0x3F);
277 static unsigned short* get_table_by_uin(char* uin
) {
279 unsigned short* table
= encoding_table
;
280 if (uin
&& qip_codepages
) {
281 if (!g_hash_table_lookup_extended(qip_codepages
, uin
, (gpointer
*)&key
, (gpointer
*)&table
)) {
282 table
= encoding_table
;
288 static gboolean
receiving_im_msg_cb(PurpleAccount
*account
, char **sender
, char **buffer
, PurpleConversation
*conv
, PurpleMessageFlags
*flags
, void *data
) {
299 unsigned short char_code
; // ansi/unicode character
300 unsigned short* table
;
302 // return immediately, if not the ICQ protocol
303 if (strcmp("prpl-icq",purple_account_get_protocol_id(account
))!=0) return FALSE
;
305 // return if fix is disabled for the UIN
306 table
= get_table_by_uin(*sender
);
307 if (!table
) return FALSE
;
310 // The following conversion is made so we almost never need message buffer
311 // memory reallocation.
313 str
= *buffer
; // position in the message
314 length
= strlen(str
);
315 remaining
= length
; // remaining chars to iterate
318 // pro each character in the message
319 for (; remaining
>0; str
++, position
++, remaining
--) {
323 // Check, if there's a broken character at the current position.
324 // If so, we'll compute the ansi code (0x80-0xFF) in char_code.
326 // The QIP uses WINDOWS-1251 character encoding, but not complete.
327 // It seems, russian authors of QIP implemented only support for
328 // russian characters, but not for other languages that are using
329 // WINDOWS-1251 encoding. Maybe, they wanted to avoid the usage of
330 // a complete convert table or system unicode functions, so they
331 // only used the approximate relationship between unicode cyrillic
332 // codes and windows codes (linear function) and corrected only
333 // a few of characters. I managed to determine the technique, so now
334 // we can perform the reverse sequence.
336 if ((c
=='&') && (remaining
>=6) && (str
[1]=='#') && (str
[2]=='x') && (str
[5]==';')) {
338 hex_digit
= HexValue(str
[3]);
339 if (hex_digit
<0) continue;
340 char_code
= hex_digit
<< 4;
341 hex_digit
= HexValue(str
[4]);
342 if (hex_digit
<0) continue;
343 char_code
+= hex_digit
;
345 } else if ((c
==(char)0xC2) && (remaining
>=2)) {
347 char_code
= str
[1] & 0xFF;
348 if (char_code
<0x80 || char_code
>0xBF) continue;
350 } else if ((c
==(char)0xD0) && (remaining
>=2)) {
352 char_code
= str
[1] & 0xFF;
353 if (char_code
== 0x81) {
356 if (char_code
<0x90 || char_code
>0xBF) continue;
360 } else if ((c
==(char)0xD1) && (remaining
>=2)) {
362 char_code
= str
[1] & 0xFF;
363 if (char_code
== 0x91) {
366 if (char_code
<0x80 || char_code
>0x8F) continue;
374 // convert native character code to unicode character
375 if (char_code
>=0x80) {
376 char_code
= table
[char_code
-0x80];
379 // now we must replace the bad character code with a right one
380 decoded_size
= UTF8Char(NULL
, char_code
);
382 // check if there's enough space to replace characters
383 if ((decoded_size
- encoded_size
) > (length
- (position
+ remaining
))) {
384 // we must realloc the message buffer;
385 // compute minimal new buffer size (plus zero term. char)
386 new_length
= position
+ remaining
+ decoded_size
- encoded_size
+ 1;
387 // ceil round to multiplier of 256
388 new_length
= ((new_length
+ 255) / 256) * 256;
390 str
= malloc(new_length
);
391 if (!str
) return TRUE
;
392 // correct size to that without zero term. char
394 // copy message begin
402 &(str
[position
+decoded_size
]),
403 &((*buffer
)[position
+encoded_size
]),
404 remaining
-encoded_size
412 remaining
+= (decoded_size
-encoded_size
);
413 encoded_size
= decoded_size
;
414 // zero the added chars
416 &((*buffer
)[position
+remaining
]),
418 length
-(position
+remaining
)+1
420 } else if (decoded_size
!=encoded_size
) {
423 &(str
[decoded_size
]),
424 &(str
[encoded_size
]),
425 remaining
-encoded_size
429 // correct the character
430 UTF8Char(str
, char_code
);
432 // zero the remaining characters
433 if (encoded_size
>decoded_size
) {
435 &(str
[remaining
-(encoded_size
-decoded_size
)]),
437 encoded_size
-decoded_size
442 position
+= (decoded_size
-1);
443 str
+= (decoded_size
-1);
444 remaining
-= (encoded_size
-1);
451 unsigned int str2intdef(const char *str
, unsigned int def
) {
453 if (!str
|| sscanf(str
,"%d",&num
)!=1) {
459 static gboolean
plugin_load(PurplePlugin
*plugin
) {
463 unsigned int codepage
;
465 gboolean default_enabled
;
466 unsigned int default_codepage
;
468 qip_codepages
= NULL
;
469 default_enabled
= TRUE
;
470 default_codepage
= 0;
472 // load codepage configuration
473 xml
= purple_util_read_xml_from_file("qips.xml","qips.xml");
475 node
= xmlnode_get_child(xml
,"default");
477 // default setting for all UINs
478 default_enabled
= str2intdef(xmlnode_get_attrib(node
,"enabled"),default_enabled
);
479 default_codepage
= str2intdef(xmlnode_get_attrib(node
,"codepage"),default_codepage
);
483 // get default codepage from system
484 if (default_codepage
<CODEPAGE_MIN
|| default_codepage
>CODEPAGE_MAX
) {
485 // try to use environment variable 'QIPACP' containing CP number
486 default_codepage
= str2intdef(getenv("QIPACP"),0);
487 if (default_codepage
<CODEPAGE_MIN
|| default_codepage
>CODEPAGE_MAX
) {
488 // now, try to use system ansi code page
489 default_codepage
= GetACP();
490 if (default_codepage
<CODEPAGE_MIN
|| default_codepage
>CODEPAGE_MAX
) {
491 default_codepage
= 0;
492 default_enabled
= FALSE
;
498 // UIN based codepage setting
499 for (node
= xmlnode_get_child(xml
,"qip"); node
; node
= xmlnode_get_next_twin(node
)) {
500 uin
= xmlnode_get_attrib(node
,"uin");
502 if (!qip_codepages
) qip_codepages
= g_hash_table_new(g_str_hash
,g_str_equal
);
503 enabled
= str2intdef(xmlnode_get_attrib(node
,"enabled"),default_enabled
);
504 codepage
= str2intdef(xmlnode_get_attrib(node
,"codepage"),default_codepage
);
506 if (!enabled
|| codepage
<CODEPAGE_MIN
|| codepage
>CODEPAGE_MAX
) codepage
= 0;
508 g_hash_table_insert(qip_codepages
,g_strdup(uin
),CODEPAGE_TABLE(codepage
));
513 // finally, assign the unicode table according to the code page
514 if (!default_enabled
) default_codepage
= 0;
515 encoding_table
= CODEPAGE_TABLE(default_codepage
);
518 purple_signal_connect(purple_conversations_get_handle(), "receiving-im-msg", plugin
, PURPLE_CALLBACK(receiving_im_msg_cb
), NULL
);
522 static gboolean
dealloc_all(gpointer key
, gpointer val
, gpointer user_data
) {
527 static gboolean
plugin_unload(PurplePlugin
*plugin
) {
528 purple_signal_disconnect(purple_conversations_get_handle(), "receiving-im-msg", plugin
, PURPLE_CALLBACK(receiving_im_msg_cb
));
531 g_hash_table_foreach_remove(qip_codepages
, dealloc_all
, NULL
);
532 g_hash_table_destroy(qip_codepages
);
533 qip_codepages
= NULL
;
538 static PurplePluginInfo info
= {
540 PURPLE_MAJOR_VERSION
,
541 PURPLE_MINOR_VERSION
,
542 PURPLE_PLUGIN_STANDARD
,
546 PURPLE_PRIORITY_DEFAULT
,
552 "QIP Decoder Plugin",
553 "Displays diacritic letters from QIP IM correctly.",
554 "Viktor Michna (viktor.michna@sedaha.cz)",
555 "http://www.sedaha.cz/qip-decoder/",
571 static void init_plugin(PurplePlugin
*plugin
) {
575 PURPLE_INIT_PLUGIN(qip
, init_plugin
, info
);
This page took 2.744207 seconds and 4 git commands to generate.