File:  [Coherent Logic Development] / ChivanetAimPidgin / oscarprpl / src / c / util.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Mon Jan 27 19:48:25 2025 UTC (6 months ago) by snw
Branches: MAIN, CoherentLogicDevelopment
CVS tags: test-tag, start, HEAD
Pidgin AIM Plugin for ChivaNet

    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.
    5:  *
    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.
   10:  *
   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.
   15:  *
   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
   19: */
   20: 
   21: /*
   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
   26:  */
   27: 
   28: #include "oscar.h"
   29: 
   30: #include "core.h"
   31: 
   32: #include <ctype.h>
   33: 
   34: #ifdef _WIN32
   35: #include "win32dep.h"
   36: #endif
   37: 
   38: static const char * const msgerrreason[] = {
   39: 	N_("Invalid error"),
   40: 	N_("Invalid SNAC"),
   41: 	N_("Server rate limit exceeded"),
   42: 	N_("Client rate limit exceeded"),
   43: 	N_("Not logged in"),
   44: 	N_("Service unavailable"),
   45: 	N_("Service not defined"),
   46: 	N_("Obsolete SNAC"),
   47: 	N_("Not supported by host"),
   48: 	N_("Not supported by client"),
   49: 	N_("Refused by client"),
   50: 	N_("Reply too big"),
   51: 	N_("Responses lost"),
   52: 	N_("Request denied"),
   53: 	N_("Busted SNAC payload"),
   54: 	N_("Insufficient rights"),
   55: 	N_("In local permit/deny"),
   56: 	N_("Warning level too high (sender)"),
   57: 	N_("Warning level too high (receiver)"),
   58: 	N_("User temporarily unavailable"),
   59: 	N_("No match"),
   60: 	N_("List overflow"),
   61: 	N_("Request ambiguous"),
   62: 	N_("Queue full"),
   63: 	N_("Not while on AOL")
   64: };
   65: static const gsize msgerrreasonlen = G_N_ELEMENTS(msgerrreason);
   66: 
   67: const char *oscar_get_msgerr_reason(size_t reason)
   68: {
   69: 	return (reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason");
   70: }
   71: 
   72: int oscar_get_ui_info_int(const char *str, int default_value)
   73: {
   74: 	GHashTable *ui_info;
   75: 
   76: 	ui_info = purple_core_get_ui_info();
   77: 	if (ui_info != NULL) {
   78: 		gpointer value;
   79: 		if (g_hash_table_lookup_extended(ui_info, str, NULL, &value))
   80: 			return GPOINTER_TO_INT(value);
   81: 	}
   82: 
   83: 	return default_value;
   84: }
   85: 
   86: const char *oscar_get_ui_info_string(const char *str, const char *default_value)
   87: {
   88: 	GHashTable *ui_info;
   89: 	const char *value = NULL;
   90: 
   91: 	ui_info = purple_core_get_ui_info();
   92: 	if (ui_info != NULL)
   93: 		value = g_hash_table_lookup(ui_info, str);
   94: 	if (value == NULL)
   95: 		value = default_value;
   96: 
   97: 	return value;
   98: }
   99: 
  100: gchar *oscar_get_clientstring(void)
  101: {
  102: 	const char *name, *version;
  103: 
  104: 	name = oscar_get_ui_info_string("name", "Purple");
  105: 	version = oscar_get_ui_info_string("version", VERSION);
  106: 
  107: 	return g_strdup_printf("%s/%s", name, version);;
  108: }
  109: 
  110: /**
  111:  * Calculate the checksum of a given icon.
  112:  */
  113: guint16
  114: aimutil_iconsum(const guint8 *buf, int buflen)
  115: {
  116: 	guint32 sum;
  117: 	int i;
  118: 
  119: 	for (i=0, sum=0; i+1<buflen; i+=2)
  120: 		sum += (buf[i+1] << 8) + buf[i];
  121: 	if (i < buflen)
  122: 		sum += buf[i];
  123: 	sum = ((sum & 0xffff0000) >> 16) + (sum & 0x0000ffff);
  124: 
  125: 	return sum;
  126: }
  127: 
  128: /**
  129:  * Check if the given name is a valid AIM username.
  130:  * Example: BobDole
  131:  * Example: Henry_Ford@mac.com
  132:  * Example: 1KrazyKat@example.com
  133:  *
  134:  * @return TRUE if the name is valid, FALSE if not.
  135:  */
  136: static gboolean
  137: oscar_util_valid_name_aim(const char *name)
  138: {
  139: 	int i;
  140: 
  141: 	if (purple_email_is_valid(name))
  142: 		return TRUE;
  143: 
  144: 	/* Normal AIM usernames can't start with a number, period or underscore */
  145: 	if (isalnum(name[0]) == 0)
  146: 		return FALSE;
  147: 
  148: 	for (i = 0; name[i] != '\0'; i++) {
  149: 		if (!isalnum(name[i]) && name[i] != ' ' && name[i] != '.' && name[i] != '_')
  150: 			return FALSE;
  151: 	}
  152: 
  153: 	return TRUE;
  154: }
  155: 
  156: /**
  157:  * Check if the given name is a valid ICQ username.
  158:  * Example: 1234567
  159:  *
  160:  * @return TRUE if the name is valid, FALSE if not.
  161:  */
  162: gboolean
  163: oscar_util_valid_name_icq(const char *name)
  164: {
  165: 	int i;
  166: 
  167: 	for (i = 0; name[i] != '\0'; i++) {
  168: 		if (!isdigit(name[i]))
  169: 			return FALSE;
  170: 	}
  171: 
  172: 	return TRUE;
  173: }
  174: 
  175: /**
  176:  * Check if the given name is a valid SMS username.
  177:  * Example: +19195551234
  178:  *
  179:  * @return TRUE if the name is valid, FALSE if not.
  180:  */
  181: gboolean
  182: oscar_util_valid_name_sms(const char *name)
  183: {
  184: 	int i;
  185: 
  186: 	if (name[0] != '+')
  187: 		return FALSE;
  188: 
  189: 	for (i = 1; name[i] != '\0'; i++) {
  190: 		if (!isdigit(name[i]))
  191: 			return FALSE;
  192: 	}
  193: 
  194: 	return TRUE;
  195: }
  196: 
  197: /**
  198:  * Check if the given name is a valid oscar username.
  199:  *
  200:  * @return TRUE if the name is valid, FALSE if not.
  201:  */
  202: gboolean
  203: oscar_util_valid_name(const char *name)
  204: {
  205: 	if ((name == NULL) || (*name == '\0'))
  206: 		return FALSE;
  207: 
  208: 	return oscar_util_valid_name_icq(name)
  209: 			|| oscar_util_valid_name_sms(name)
  210: 			|| oscar_util_valid_name_aim(name);
  211: }
  212: 
  213: /**
  214:  * This takes two names and compares them using the rules
  215:  * on usernames for AIM/AOL.  Mainly, this means case and space
  216:  * insensitivity (all case differences and spacing differences are
  217:  * ignored, with the exception that usernames can not start with
  218:  * a space).
  219:  *
  220:  * @return 0 if equal, non-0 if different
  221:  */
  222: /* TODO: Do something different for email addresses. */
  223: int
  224: oscar_util_name_compare(const char *name1, const char *name2)
  225: {
  226: 
  227: 	if ((name1 == NULL) || (name2 == NULL))
  228: 		return -1;
  229: 
  230: 	do {
  231: 		while (*name2 == ' ')
  232: 			name2++;
  233: 		while (*name1 == ' ')
  234: 			name1++;
  235: 		if (toupper(*name1) != toupper(*name2))
  236: 			return 1;
  237: 	} while ((*name1 != '\0') && name1++ && name2++);
  238: 
  239: 	return 0;
  240: }
  241: 
  242: /**
  243:  * Looks for %n, %d, or %t in a string, and replaces them with the
  244:  * specified name, date, and time, respectively.
  245:  *
  246:  * @param str  The string that may contain the special variables.
  247:  * @param name The sender name.
  248:  *
  249:  * @return A newly allocated string where the special variables are
  250:  *         expanded.  This should be g_free'd by the caller.
  251:  */
  252: gchar *
  253: oscar_util_format_string(const char *str, const char *name)
  254: {
  255: 	char *c;
  256: 	GString *cpy;
  257: 	time_t t;
  258: 	struct tm *tme;
  259: 
  260: 	g_return_val_if_fail(str  != NULL, NULL);
  261: 	g_return_val_if_fail(name != NULL, NULL);
  262: 
  263: 	/* Create an empty GString that is hopefully big enough for most messages */
  264: 	cpy = g_string_sized_new(1024);
  265: 
  266: 	t = time(NULL);
  267: 	tme = localtime(&t);
  268: 
  269: 	c = (char *)str;
  270: 	while (*c) {
  271: 		switch (*c) {
  272: 		case '%':
  273: 			if (*(c + 1)) {
  274: 				switch (*(c + 1)) {
  275: 				case 'n':
  276: 					/* append name */
  277: 					g_string_append(cpy, name);
  278: 					c++;
  279: 					break;
  280: 				case 'd':
  281: 					/* append date */
  282: 					g_string_append(cpy, purple_date_format_short(tme));
  283: 					c++;
  284: 					break;
  285: 				case 't':
  286: 					/* append time */
  287: 					g_string_append(cpy, purple_time_format(tme));
  288: 					c++;
  289: 					break;
  290: 				default:
  291: 					g_string_append_c(cpy, *c);
  292: 				}
  293: 			} else {
  294: 				g_string_append_c(cpy, *c);
  295: 			}
  296: 			break;
  297: 		default:
  298: 			g_string_append_c(cpy, *c);
  299: 		}
  300: 		c++;
  301: 	}
  302: 
  303: 	return g_string_free(cpy, FALSE);
  304: }
  305: 
  306: gchar *
  307: oscar_format_buddies(GSList *buddies, const gchar *no_buddies_message)
  308: {
  309: 	GSList *cur;
  310: 	GString *result;
  311: 	if (!buddies) {
  312: 		return g_strdup_printf("<i>%s</i>", no_buddies_message);
  313: 	}
  314: 	result = g_string_new("");
  315: 	for (cur = buddies; cur != NULL; cur = cur->next) {
  316: 		PurpleBuddy *buddy = cur->data;
  317: 		const gchar *bname = purple_buddy_get_name(buddy);
  318: 		const gchar *alias = purple_buddy_get_alias_only(buddy);
  319: 		g_string_append(result, bname);
  320: 		if (alias) {
  321: 			g_string_append_printf(result, " (%s)", alias);
  322: 		}
  323: 		g_string_append(result, "<br>");
  324: 	}
  325: 	return g_string_free(result, FALSE);
  326: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>