1 /* Misc utility functions for the Pidgin-Encryption plugin */
2 /* Copyright (C) 2001-2003 William Tompkins */
3
4 /* This plugin is free software, distributed under the GNU General Public */
5 /* License. */
6 /* Please see the file "COPYING" distributed with this source code */
7 /* for more details */
8 /* */
9 /* */
10 /* This software is distributed in the hope that it will be useful, */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
13 /* General Public License for more details. */
14
15 /* To compile and use: */
16 /* See INSTALL file. */
17
18 #include "internal.h"
19
20 #include <string.h>
21 #include <stdlib.h>
22
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <errno.h>
27 #include <unistd.h>
28
29
30 #include <debug.h>
31
32 #ifdef _WIN32
33 #include <win32dep.h>
34 #endif
35
36 #include "nls.h"
37 #include "cryptutil.h"
38 #include "rsa_nss.h"
39
40 #include <base64.h>
41
42
43
PE_clear_string(char * s)44 void PE_clear_string(char* s) {
45 while(*s != 0) {
46 *(s++) = 0;
47 }
48 }
49
PE_escape_name(GString * name)50 void PE_escape_name(GString* name) {
51 int pos = 0;
52
53 // Note: name->len and name->str can change as we modify name...
54 while (pos < name->len) {
55 switch (name->str[pos]) {
56 case ' ':
57 // space -> "\s"
58 g_string_erase(name, pos, 1);
59 g_string_insert(name, pos, "\\s");
60 pos += 2;
61 break;
62 case ',':
63 // comma -> "\c"
64 g_string_erase(name, pos, 1);
65 g_string_insert(name, pos, "\\c");
66 pos += 2;
67 break;
68 case '\\':
69 // backslash -> "\\"
70 g_string_erase(name, pos, 1);
71 g_string_insert(name, pos, "\\");
72 pos += 2;
73 break;
74 default:
75 ++pos;
76 break;
77 }
78 }
79 }
80
PE_unescape_name(char * origname)81 void PE_unescape_name(char* origname) {
82 GString *name = g_string_new(origname);
83 int pos = 0;
84
85 while (pos < name->len) {
86 if (name->str[pos] == '\\') {
87 g_string_erase(name, pos, 1);
88 switch (name->str[pos]) {
89 case 's':
90 // \s -> space
91 name->str[pos] = ' ';
92 ++pos;
93 break;
94 case 'c':
95 // \c -> comma
96 name->str[pos] = ',';
97 ++pos;
98 break;
99 default:
100 // leave the char that followed the backslash
101 ++pos;
102 break;
103 }
104 } else {
105 ++pos;
106 }
107 }
108
109 // string can only be shorter, so this copy is ok
110 strcpy(origname, name->str);
111
112 g_string_free(name, TRUE);
113 }
114
115 /* Convert 'num' bytes into an ascii string. */
PE_bytes_to_str(char * str,unsigned char * bytes,int num)116 void PE_bytes_to_str(char *str, unsigned char *bytes, int num) {
117 char* tmp = BTOA_DataToAscii(bytes, num);
118 GString* tmp2 = g_string_new(tmp);
119
120 PE_strip_returns(tmp2);
121 strcpy(str, tmp2->str);
122
123 PORT_Free(tmp);
124 g_string_free(tmp2, TRUE);
125 }
126
127 /* Convert ascii string back into bytes. Returns number of bytes */
PE_str_to_bytes(unsigned char * bytes,char * cstr)128 unsigned int PE_str_to_bytes(unsigned char *bytes, char *cstr) {
129 unsigned int tmplen;
130 unsigned char* tmp = ATOB_AsciiToData(cstr, &tmplen);
131 if (tmp == NULL) {
132 purple_debug(PURPLE_DEBUG_ERROR, "pidgin-encryption", _("Invalid Base64 data, length %u\n"),
133 (unsigned)strlen(cstr));
134 return 0;
135 }
136
137 memcpy(bytes, tmp, tmplen);
138 PORT_Free(tmp);
139
140 return tmplen;
141 }
142
143
PE_strip_returns(GString * s)144 GString* PE_strip_returns(GString* s) {
145 gchar *strippedStr, **strArray;
146 int i;
147
148 strArray = g_strsplit(s->str, "\n", 100);
149
150 for (i = 0; strArray[i] != 0; ++i) {
151 g_strstrip(strArray[i]);
152 }
153
154 strippedStr = g_strjoinv(0, strArray);
155
156 g_string_assign(s, strippedStr);
157
158 g_strfreev(strArray);
159 g_free(strippedStr);
160 return s;
161 }
162
PE_msg_starts_with_link(const char * c)163 gboolean PE_msg_starts_with_link(const char* c) {
164 /* This seems easy. But, we need to filter out intermediate HTML
165 (like <font>) as well. And, to be really compliant, we should
166 parse things like "< a href=" (even if noone else seems to).
167 */
168
169 while (*c != 0) {
170 /* If we don't start with a tag, we can't start with a link */
171 if (*(c++) != '<') return FALSE;
172
173 while (isspace(*c)) ++c; /* skip leading whitespace in tag */
174 if (*c == 'A' || *c == 'a') return TRUE;
175 c = strchr(c, '>'); /* skip to end of tag */
176 if (*c) ++c; /* watch out for unclosed tags! */
177 }
178 return FALSE;
179 }
180
181 /* Removed from Gaim/Pidgin, so added in here :) */
182
PE_message_split(char * message,int limit)183 GSList *PE_message_split(char *message, int limit) {
184 static GSList *ret = NULL;
185 int lastgood = 0, curgood = 0, curpos = 0, len = strlen(message);
186 gboolean intag = FALSE;
187
188 if (ret) {
189 GSList *tmp = ret;
190 while (tmp) {
191 g_free(tmp->data);
192 tmp = g_slist_remove(tmp, tmp->data);
193 }
194 ret = NULL;
195 }
196
197 while (TRUE) {
198 if (lastgood >= len)
199 return ret;
200
201 if (len - lastgood < limit) {
202 ret = g_slist_append(ret, g_strdup(&message[lastgood]));
203 return ret;
204 }
205
206 curgood = curpos = 0;
207 intag = FALSE;
208 while (curpos <= limit) {
209 if (isspace(message[curpos + lastgood]) && !intag)
210 curgood = curpos;
211 if (message[curpos + lastgood] == '<')
212 intag = TRUE;
213 if (message[curpos + lastgood] == '>')
214 intag = FALSE;
215 curpos++;
216 }
217
218 if (curgood) {
219 ret = g_slist_append(ret, g_strndup(&message[lastgood], curgood));
220 if (isspace(message[curgood + lastgood]))
221 lastgood += curgood + 1;
222 else
223 lastgood += curgood;
224 } else {
225 /* whoops, guess we have to fudge it here */
226 ret = g_slist_append(ret, g_strndup(&message[lastgood], limit));
227 lastgood += limit;
228 }
229 }
230 }
231
232
233
234 /* Old versions of utility functions, using Base16 rather than Base64 */
235
236
237 /* Note: str will _NOT_ be null terminated. Its length will be returned
238 from the function */
239
240 /* int PE_bytes_to_colonstr(unsigned char *str, unsigned char *bytes, int num) { */
241 /* int bytes_cursor=0, str_cursor=0; */
242
243 /* while (bytes_cursor < num) { */
244 /* sprintf(str + str_cursor, "%02x", bytes[bytes_cursor++]); */
245 /* str_cursor += 2; */
246 /* if (bytes_cursor < num) str[str_cursor++] = ':'; */
247 /* } */
248
249 /* return str_cursor; */
250 /* } */
251
252 /* /\* Note: str will _NOT_ be null terminated. Its length will be returned */
253 /* from the function *\/ */
254 /* int PE_bytes_to_str(unsigned char *str, unsigned char *bytes, int num) { */
255 /* int bytes_cursor=0, str_cursor=0; */
256
257 /* while (bytes_cursor < num) { */
258 /* sprintf(str + str_cursor, "%02x", bytes[bytes_cursor++]); */
259 /* str_cursor += 2; */
260 /* } */
261 /* return str_cursor; */
262 /* } */
263
264 /* /\* Note: str does not need to be null terminated. num bytes are pulled */
265 /* off the string (unless the end of the string is reached first). */
266 /* The number of chars pulled off the string is returned, or -1 */
267 /* if there is an error or the end of the string is reached first. *\/ */
268
269 /* int PE_nstr_to_bytes(unsigned char *bytes, unsigned char *nstr, int num) { */
270 /* int bytes_cursor, str_cursor = 0; */
271 /* unsigned char minibuf[3] = "00"; */
272
273 /* for (bytes_cursor = 0; bytes_cursor < num; ++bytes_cursor) { */
274 /* minibuf[0] = nstr[str_cursor++]; */
275 /* if (minibuf[0] == 0) return -1; */
276 /* minibuf[1] = nstr[str_cursor++]; */
277 /* if (minibuf[1] == 0) return -1; */
278 /* bytes[bytes_cursor] = (unsigned char) strtoul(minibuf, 0, 16); */
279 /* } */
280 /* return str_cursor; */
281 /* } */
282
283 /* /\* Note: cstr must be null terminated. Up to num bytes are pulled */
284 /* off the string (unless the end of the string is reached first). */
285 /* The number of bytes gotten is returned. */
286 /* A parse error returns -1 *\/ */
287
288 /* int PE_cstr_to_bytes(unsigned char *bytes, unsigned char *cstr, int num) { */
289 /* int bytes_cursor, str_cursor = 0; */
290 /* unsigned char minibuf[3] = "00"; */
291
292 /* for (bytes_cursor = 0; bytes_cursor < num; ++bytes_cursor) { */
293 /* minibuf[0] = cstr[str_cursor++]; */
294 /* if (minibuf[0] == 0) return bytes_cursor; */
295 /* minibuf[1] = cstr[str_cursor++]; */
296 /* if (minibuf[1] == 0) return -1; */
297 /* bytes[bytes_cursor] = (unsigned char) strtoul(minibuf, 0, 16); */
298 /* } */
299 /* return bytes_cursor; */
300 /* } */
301
302