rename accountopt.[ch] to purpleaccountoption.[ch]
[pidgin-git.git] / libpurple / protocols / oscar / util.c
blob3d3923aeb0f3b02cfa737c251f9fb0cdc0e4ef65
1 /*
2 * Purple's oscar protocol plugin
3 * This file is the legal property of its developers.
4 * Please see the AUTHORS file distributed alongside this file.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library 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 GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
22 * A little bit of this
23 * A little bit of that
24 * It started with a kiss
25 * Now we're up to bat
28 #include "oscar.h"
30 #include "core.h"
32 #include <ctype.h>
34 static const char * const msgerrreason[] = {
35 N_("Invalid error"),
36 N_("Invalid SNAC"),
37 N_("Server rate limit exceeded"),
38 N_("Client rate limit exceeded"),
39 N_("Not logged in"),
40 N_("Service unavailable"),
41 N_("Service not defined"),
42 N_("Obsolete SNAC"),
43 N_("Not supported by host"),
44 N_("Not supported by client"),
45 N_("Refused by client"),
46 N_("Reply too big"),
47 N_("Responses lost"),
48 N_("Request denied"),
49 N_("Busted SNAC payload"),
50 N_("Insufficient rights"),
51 N_("In local permit/deny"),
52 N_("Warning level too high (sender)"),
53 N_("Warning level too high (receiver)"),
54 N_("User temporarily unavailable"),
55 N_("No match"),
56 N_("List overflow"),
57 N_("Request ambiguous"),
58 N_("Queue full"),
59 N_("Not while on AOL")
61 static const gsize msgerrreasonlen = G_N_ELEMENTS(msgerrreason);
63 const char *oscar_get_msgerr_reason(size_t reason)
65 return (reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason");
68 int oscar_get_ui_info_int(const char *str, int default_value)
70 GHashTable *ui_info;
72 ui_info = purple_core_get_ui_info();
73 if (ui_info != NULL) {
74 gpointer value;
75 if (g_hash_table_lookup_extended(ui_info, str, NULL, &value))
76 return GPOINTER_TO_INT(value);
79 return default_value;
82 const char *oscar_get_ui_info_string(const char *str, const char *default_value)
84 GHashTable *ui_info;
85 const char *value = NULL;
87 ui_info = purple_core_get_ui_info();
88 if (ui_info != NULL)
89 value = g_hash_table_lookup(ui_info, str);
90 if (value == NULL)
91 value = default_value;
93 return value;
96 gchar *oscar_get_clientstring(void)
98 const char *name, *version;
100 name = oscar_get_ui_info_string("name", "Purple");
101 version = oscar_get_ui_info_string("version", VERSION);
103 return g_strdup_printf("%s/%s", name, version);;
107 * Calculate the checksum of a given icon.
109 guint16
110 aimutil_iconsum(const guint8 *buf, int buflen)
112 guint32 sum;
113 int i;
115 for (i=0, sum=0; i+1<buflen; i+=2)
116 sum += (buf[i+1] << 8) + buf[i];
117 if (i < buflen)
118 sum += buf[i];
119 sum = ((sum & 0xffff0000) >> 16) + (sum & 0x0000ffff);
121 return sum;
125 * Check if the given name is a valid AIM username.
126 * Example: BobDole
127 * Example: Henry_Ford@mac.com
128 * Example: 1KrazyKat@example.com
130 * @return TRUE if the name is valid, FALSE if not.
132 static gboolean
133 oscar_util_valid_name_aim(const char *name)
135 int i;
137 if (purple_email_is_valid(name))
138 return TRUE;
140 /* Normal AIM usernames can't start with a number, period or underscore */
141 if (isalnum(name[0]) == 0)
142 return FALSE;
144 for (i = 0; name[i] != '\0'; i++) {
145 if (!isalnum(name[i]) && name[i] != ' ' && name[i] != '.' && name[i] != '_')
146 return FALSE;
149 return TRUE;
153 * Check if the given name is a valid ICQ username.
154 * Example: 1234567
156 * @return TRUE if the name is valid, FALSE if not.
158 gboolean
159 oscar_util_valid_name_icq(const char *name)
161 int i;
163 for (i = 0; name[i] != '\0'; i++) {
164 if (!isdigit(name[i]))
165 return FALSE;
168 return TRUE;
172 * Check if the given name is a valid SMS username.
173 * Example: +19195551234
175 * @return TRUE if the name is valid, FALSE if not.
177 gboolean
178 oscar_util_valid_name_sms(const char *name)
180 int i;
182 if (name[0] != '+')
183 return FALSE;
185 for (i = 1; name[i] != '\0'; i++) {
186 if (!isdigit(name[i]))
187 return FALSE;
190 return TRUE;
194 * Check if the given name is a valid oscar username.
196 * @return TRUE if the name is valid, FALSE if not.
198 gboolean
199 oscar_util_valid_name(const char *name)
201 if ((name == NULL) || (*name == '\0'))
202 return FALSE;
204 return oscar_util_valid_name_icq(name)
205 || oscar_util_valid_name_sms(name)
206 || oscar_util_valid_name_aim(name);
210 * This takes two names and compares them using the rules
211 * on usernames for AIM/AOL. Mainly, this means case and space
212 * insensitivity (all case differences and spacing differences are
213 * ignored, with the exception that usernames can not start with
214 * a space).
216 * @return 0 if equal, non-0 if different
218 /* TODO: Do something different for email addresses. */
220 oscar_util_name_compare(const char *name1, const char *name2)
223 if ((name1 == NULL) || (name2 == NULL))
224 return -1;
226 do {
227 while (*name2 == ' ')
228 name2++;
229 while (*name1 == ' ')
230 name1++;
231 if (toupper(*name1) != toupper(*name2))
232 return 1;
233 } while ((*name1 != '\0') && name1++ && name2++);
235 return 0;
239 * Looks for %n, %d, or %t in a string, and replaces them with the
240 * specified name, date, and time, respectively.
242 * @param str The string that may contain the special variables.
243 * @param name The sender name.
245 * @return A newly allocated string where the special variables are
246 * expanded. This should be g_free'd by the caller.
248 gchar *
249 oscar_util_format_string(const char *str, const char *name)
251 char *c;
252 GString *cpy;
253 time_t t;
254 struct tm *tme;
256 g_return_val_if_fail(str != NULL, NULL);
257 g_return_val_if_fail(name != NULL, NULL);
259 /* Create an empty GString that is hopefully big enough for most messages */
260 cpy = g_string_sized_new(1024);
262 t = time(NULL);
263 tme = localtime(&t);
265 c = (char *)str;
266 while (*c) {
267 switch (*c) {
268 case '%':
269 if (*(c + 1)) {
270 switch (*(c + 1)) {
271 case 'n':
272 /* append name */
273 g_string_append(cpy, name);
274 c++;
275 break;
276 case 'd':
277 /* append date */
278 g_string_append(cpy, purple_date_format_short(tme));
279 c++;
280 break;
281 case 't':
282 /* append time */
283 g_string_append(cpy, purple_time_format(tme));
284 c++;
285 break;
286 default:
287 g_string_append_c(cpy, *c);
289 } else {
290 g_string_append_c(cpy, *c);
292 break;
293 default:
294 g_string_append_c(cpy, *c);
296 c++;
299 return g_string_free(cpy, FALSE);
302 gchar *
303 oscar_format_buddies(GSList *buddies, const gchar *no_buddies_message)
305 GSList *cur;
306 GString *result;
307 if (!buddies) {
308 return g_strdup_printf("<i>%s</i>", no_buddies_message);
310 result = g_string_new("");
311 for (cur = buddies; cur != NULL; cur = cur->next) {
312 PurpleBuddy *buddy = cur->data;
313 const gchar *bname = purple_buddy_get_name(buddy);
314 const gchar *alias = purple_buddy_get_alias_only(buddy);
315 g_string_append(result, bname);
316 if (alias) {
317 g_string_append_printf(result, " (%s)", alias);
319 g_string_append(result, "<br>");
321 return g_string_free(result, FALSE);