Mercurial > pidgin
diff src/util.c @ 7108:6faeeecab0dc
[gaim-migrate @ 7673]
Put the rest of util.[ch] into namespaces and sectioned off the functions.
committer: Tailor Script <tailor@pidgin.im>
author | Christian Hammond <chipx86@chipx86.com> |
---|---|
date | Wed, 01 Oct 2003 07:15:53 +0000 |
parents | 9220c7490cd1 |
children | b003397b16fe |
line wrap: on
line diff
--- a/src/util.c Wed Oct 01 06:17:28 2003 +0000 +++ b/src/util.c Wed Oct 01 07:15:53 2003 +0000 @@ -60,122 +60,121 @@ static char home_dir[MAXPATHLEN]; -char *full_date() -{ - char *date; - time_t tme; - time(&tme); - date = ctime(&tme); - date[strlen(date) - 1] = '\0'; - return date; -} - -G_GNUC_CONST static gint badchar(char c) +/************************************************************************** + * Base16 Functions + **************************************************************************/ +unsigned char * +gaim_base16_encode(const unsigned char *data, int length) { - switch (c) { - case ' ': - case ',': - case '(': - case ')': - case '\0': - case '\n': - case '<': - case '>': - case '"': - case '\'': - return 1; - default: - return 0; - } + int i; + unsigned char *ascii = NULL; + + g_return_val_if_fail(data != NULL, NULL); + g_return_val_if_fail(length > 0, NULL); + + ascii = g_malloc(length * 2 + 1); + + for (i = 0; i < length; i++) + snprintf(&ascii[i * 2], 3, "%02hhx", data[i]); + + return ascii; } - -gchar *sec_to_text(guint sec) +int +gaim_base16_decode(const char *ascii, unsigned char **raw) { - guint daze, hrs, min; - char *ret = NULL; + int len, i, accumulator = 0; + unsigned char *data; + + g_return_val_if_fail(ascii != NULL, 0); - daze = sec / (60 * 60 * 24); - hrs = (sec % (60 * 60 * 24)) / (60 * 60); - min = (sec % (60 * 60)) / 60; - sec = min % 60; + len = strlen(ascii); + + g_return_val_if_fail(strlen(ascii) > 0, 0); + g_return_val_if_fail(len % 2 > 0, 0); + + data = g_malloc(len / 2); - if (daze) { - if (hrs || min) { - if (hrs) { - if (min) { - ret = g_strdup_printf( - "%d %s, %d %s, %d %s.", - daze, ngettext("day","days",daze), - hrs, ngettext("hour","hours",hrs), min, ngettext("minute","minutes",min)); - } else { - ret = g_strdup_printf( - "%d %s, %d %s.", - daze, ngettext("day","days",daze), hrs, ngettext("hour","hours",hrs)); - } - } else { - ret = g_strdup_printf( - "%d %s, %d %s.", - daze, ngettext("day","days",daze), min, ngettext("minute","minutes",min)); + for (i = 0; i < len; i++) + { + if ((i % 2) == 0) + accumulator = 0; + else + accumulator <<= 4; + + if (isdigit(ascii[i])) + accumulator |= ascii[i] - 48; + else + { + switch(ascii[i]) + { + case 'a': case 'A': accumulator |= 10; break; + case 'b': case 'B': accumulator |= 11; break; + case 'c': case 'C': accumulator |= 12; break; + case 'd': case 'D': accumulator |= 13; break; + case 'e': case 'E': accumulator |= 14; break; + case 'f': case 'F': accumulator |= 15; break; } - } else - ret = g_strdup_printf("%d %s.", daze, ngettext("day","days",daze)); - } else { - if (hrs) { - if (min) { - ret = g_strdup_printf( - "%d %s, %d %s.", - hrs, ngettext("hour","hours",hrs), min, ngettext("minute","minutes",min)); - } else { - ret = g_strdup_printf("%d %s.", hrs, ngettext("hour","hours",hrs)); - } - } else { - ret = g_strdup_printf("%d %s.", min, ngettext("minute","minutes",min)); } + + if (i % 2) + data[(i - 1) / 2] = accumulator; } - return ret; + *raw = data; + + return (len / 2); } - +/************************************************************************** + * Base64 Functions + **************************************************************************/ static const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" "0123456789+/"; -char *gaim_base64_encode(const unsigned char *in, size_t inlen) +unsigned char * +gaim_base64_encode(const unsigned char *in, size_t inlen) { char *out, *rv; + g_return_val_if_fail(in != NULL, NULL); + g_return_val_if_fail(inlen > 0, NULL); + rv = out = g_malloc((4 * (inlen + 1)) / 3 + 1); - for (; inlen >= 3; inlen -= 3) - { - *out++ = alphabet[in[0] >> 2]; - *out++ = alphabet[((in[0] << 4) & 0x30) | (in[1] >> 4)]; - *out++ = alphabet[((in[1] << 2) & 0x3c) | (in[2] >> 6)]; - *out++ = alphabet[in[2] & 0x3f]; - in += 3; - } - if (inlen > 0) - { - unsigned char fragment; + for (; inlen >= 3; inlen -= 3) + { + *out++ = alphabet[in[0] >> 2]; + *out++ = alphabet[((in[0] << 4) & 0x30) | (in[1] >> 4)]; + *out++ = alphabet[((in[1] << 2) & 0x3c) | (in[2] >> 6)]; + *out++ = alphabet[in[2] & 0x3f]; + in += 3; + } + + if (inlen > 0) + { + unsigned char fragment; - *out++ = alphabet[in[0] >> 2]; - fragment = (in[0] << 4) & 0x30; - if (inlen > 1) - fragment |= in[1] >> 4; - *out++ = alphabet[fragment]; - *out++ = (inlen < 2) ? '=' : alphabet[(in[1] << 2) & 0x3c]; - *out++ = '='; - } - *out = '\0'; + *out++ = alphabet[in[0] >> 2]; + fragment = (in[0] << 4) & 0x30; + + if (inlen > 1) + fragment |= in[1] >> 4; + + *out++ = alphabet[fragment]; + *out++ = (inlen < 2) ? '=' : alphabet[(in[1] << 2) & 0x3c]; + *out++ = '='; + } + + *out = '\0'; return rv; } - -void gaim_base64_decode(const char *text, char **data, int *size) +void +gaim_base64_decode(const char *text, char **data, int *size) { char *out = NULL; char tmp = 0; @@ -183,8 +182,8 @@ gint32 tmp2 = 0; int len = 0, n = 0; - if (!text || !data) - return; + g_return_if_fail(text != NULL); + g_return_if_fail(data != NULL); c = text; @@ -236,343 +235,42 @@ out[len] = 0; *data = out; + if (size) *size = len; } -/* - * Converts raw data to a pretty, null-terminated base16 string. - */ -unsigned char *gaim_base16_encode(const unsigned char *data, int length) -{ - int i; - unsigned char *ascii = NULL; - if (!data || !length) - return NULL; - - ascii = g_malloc(length*2 + 1); - - for (i=0; i<length; i++) - snprintf(&ascii[i*2], 3, "%02hhx", data[i]); - - return ascii; -} - -/* - * Converts a null-terminated string of hexidecimal to raw data. - */ -int gaim_base16_decode(const char *ascii, unsigned char **raw) -{ - int len, i, accumulator=0; - unsigned char *data; - - if (!ascii || !(len = strlen(ascii)) || (len % 2)) - return 0; - - data = g_malloc(len/2); - for (i=0; i<len; i++) { - if (!(i % 2)) - accumulator = 0; - else - accumulator = accumulator << 4; - if (isdigit(ascii[i])) - accumulator |= ascii[i]-48; - else switch(ascii[i]) { - case 'a': case 'A': accumulator|=10; break; - case 'b': case 'B': accumulator|=11; break; - case 'c': case 'C': accumulator|=12; break; - case 'd': case 'D': accumulator|=13; break; - case 'e': case 'E': accumulator|=14; break; - case 'f': case 'F': accumulator|=15; break; - } - if (i % 2) - data[(i-1)/2] = accumulator; - } - - *raw = data; - return len/2; -} - -char *gaim_normalize(const char *s) -{ - static char buf[BUF_LEN]; - char *tmp; - int i, j; - - g_return_val_if_fail((s != NULL), NULL); - - strncpy(buf, s, BUF_LEN); - for (i=0, j=0; buf[j]; i++, j++) { - while (buf[j] == ' ') - j++; - buf[i] = buf[j]; - } - buf[i] = '\0'; - - tmp = g_utf8_strdown(buf, -1); - g_snprintf(buf, sizeof(buf), "%s", tmp); - g_free(tmp); - tmp = g_utf8_normalize(buf, -1, G_NORMALIZE_DEFAULT); - g_snprintf(buf, sizeof(buf), "%s", tmp); - g_free(tmp); - - return buf; -} - -char *date() +/************************************************************************** + * Date/Time Functions + **************************************************************************/ +char * +gaim_date(void) { static char date[80]; time_t tme; + time(&tme); strftime(date, sizeof(date), "%H:%M:%S", localtime(&tme)); + return date; } -/* Look for %n, %d, or %t in msg, and replace with the sender's name, date, - or time */ -char *away_subs(const char *msg, const char *name) -{ - char *c; - static char cpy[BUF_LONG]; - int cnt = 0; - time_t t = time(0); - struct tm *tme = localtime(&t); - char tmp[20]; - - cpy[0] = '\0'; - c = (char *)msg; - while (*c) { - switch (*c) { - case '%': - if (*(c + 1)) { - switch (*(c + 1)) { - case 'n': - /* append name */ - strcpy(cpy + cnt, name); - cnt += strlen(name); - c++; - break; - case 'd': - /* append date */ - strftime(tmp, 20, "%m/%d/%Y", tme); - strcpy(cpy + cnt, tmp); - cnt += strlen(tmp); - c++; - break; - case 't': - /* append time */ - strftime(tmp, 20, "%r", tme); - strcpy(cpy + cnt, tmp); - cnt += strlen(tmp); - c++; - break; - default: - cpy[cnt++] = *c; - } - } - break; - default: - cpy[cnt++] = *c; - } - c++; - } - cpy[cnt] = '\0'; - return (cpy); -} - -GSList *message_split(char *message, int limit) +char * +gaim_date_full(void) { - static GSList *ret = NULL; - int lastgood = 0, curgood = 0, curpos = 0, len = strlen(message); - gboolean intag = FALSE; - - if (ret) { - GSList *tmp = ret; - while (tmp) { - g_free(tmp->data); - tmp = g_slist_remove(tmp, tmp->data); - } - ret = NULL; - } - - while (TRUE) { - if (lastgood >= len) - return ret; - - if (len - lastgood < limit) { - ret = g_slist_append(ret, g_strdup(&message[lastgood])); - return ret; - } + char *date; + time_t tme; - curgood = curpos = 0; - intag = FALSE; - while (curpos <= limit) { - if (isspace(message[curpos + lastgood]) && !intag) - curgood = curpos; - if (message[curpos + lastgood] == '<') - intag = TRUE; - if (message[curpos + lastgood] == '>') - intag = FALSE; - curpos++; - } + time(&tme); + date = ctime(&tme); + date[strlen(date) - 1] = '\0'; - if (curgood) { - ret = g_slist_append(ret, g_strndup(&message[lastgood], curgood)); - if (isspace(message[curgood + lastgood])) - lastgood += curgood + 1; - else - lastgood += curgood; - } else { - /* whoops, guess we have to fudge it here */ - ret = g_slist_append(ret, g_strndup(&message[lastgood], limit)); - lastgood += limit; - } - } -} - -const gchar *gaim_home_dir() -{ -#ifndef _WIN32 - if(g_get_home_dir()) - return g_get_home_dir(); - else - return NULL; -#else - return wgaim_data_dir(); -#endif + return date; } -/* returns a string of the form ~/.gaim, where ~ is replaced by the user's home - * dir. Note that there is no trailing slash after .gaim. */ -gchar *gaim_user_dir() -{ - const gchar *hd = gaim_home_dir(); - if(hd) { - strcpy( (char*)&home_dir, hd ); - strcat( (char*)&home_dir, G_DIR_SEPARATOR_S ".gaim" ); - return (gchar*)&home_dir; - } - else { - return NULL; - } -} - -/* - * rcg10312000 This could be more robust, but it works for my current - * goal: to remove those annoying <BR> tags. :) - * dtf12162000 made the loop more readable. i am a neat freak. ;) */ -void strncpy_nohtml(gchar *dest, const gchar *src, size_t destsize) -{ - gchar *ptr; - g_snprintf(dest, destsize, "%s", src); - - while ((ptr = strstr(dest, "<BR>")) != NULL) { - /* replace <BR> with a newline. */ - *ptr = '\n'; - memmove(ptr + 1, ptr + 4, strlen(ptr + 4) + 1); - } -} - -void strncpy_withhtml(gchar *dest, const gchar *src, size_t destsize) -{ - gchar *end = dest + destsize; - - while (dest < end) { - if (*src == '\n' && dest < end - 5) { - strcpy(dest, "<BR>"); - src++; - dest += 4; - } else if(*src == '\r') { - src++; - } else { - *dest++ = *src; - if (*src == '\0') - return; - else - src++; - } - } -} - - -/* - * Like strncpy_withhtml (above), but malloc()'s the necessary space - * - * The caller is responsible for freeing the space pointed to by the - * return value. - */ - -gchar *strdup_withhtml(const gchar *src) -{ - gchar *sp, *dest; - gulong destsize; - - if(!src) - return NULL; - - /* - * All we need do is multiply the number of newlines by 3 (the - * additional length of "<BR>" over "\n"), account for the - * terminator, malloc the space and call strncpy_withhtml. - */ - for(destsize = 0, sp = (gchar *)src; (sp = strchr(sp, '\n')) != NULL; ++sp, ++destsize) - ; - destsize *= 3; - destsize += strlen(src) + 1; - dest = g_malloc(destsize); - strncpy_withhtml(dest, src, destsize); - - return(dest); -} - -void strip_linefeed(gchar *text) -{ - int i, j; - gchar *text2 = g_malloc(strlen(text) + 1); - - for (i = 0, j = 0; text[i]; i++) - if (text[i] != '\r') - text2[j++] = text[i]; - text2[j] = '\0'; - - strcpy(text, text2); - g_free(text2); -} - -char *add_cr(const char *text) -{ - char *ret = NULL; - int count = 0, i, j; - - if (text[0] == '\n') - count++; - for (i = 1; i < strlen(text); i++) - if (text[i] == '\n' && text[i - 1] != '\r') - count++; - - if (count == 0) - return g_strdup(text); - - ret = g_malloc0(strlen(text) + count + 1); - - i = 0; j = 0; - if (text[i] == '\n') - ret[j++] = '\r'; - ret[j++] = text[i++]; - for (; i < strlen(text); i++) { - if (text[i] == '\n' && text[i - 1] != '\r') - ret[j++] = '\r'; - ret[j++] = text[i]; - } - - gaim_debug(GAIM_DEBUG_INFO, "add_cr", "got: %s, leaving with %s\n", - text, ret); - - return ret; -} - -time_t get_time(int year, int month, int day, int hour, int min, int sec) +time_t +gaim_time_build(int year, int month, int day, int hour, int min, int sec) { struct tm tm; @@ -582,227 +280,14 @@ tm.tm_hour = hour; tm.tm_min = min; tm.tm_sec = sec >= 0 ? sec : time(NULL) % 60; + return mktime(&tm); } -/* - * Like mkstemp() but returns a file pointer, uses a pre-set template, - * uses the semantics of tempnam() for the directory to use and allocates - * the space for the filepath. - * - * Caller is responsible for closing the file and removing it when done, - * as well as freeing the space pointed-to by "path" with g_free(). - * - * Returns NULL on failure and cleans up after itself if so. - */ -static const char *gaim_mkstemp_templ = {"gaimXXXXXX"}; -FILE *gaim_mkstemp(gchar **fpath) -{ - const gchar *tmpdir; -#ifndef _WIN32 - int fd; -#endif - FILE *fp = NULL; - - if((tmpdir = (gchar*)g_get_tmp_dir()) != NULL) { - if((*fpath = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", tmpdir, gaim_mkstemp_templ)) != NULL) { -#ifdef _WIN32 - char* result = _mktemp( *fpath ); - if( result == NULL ) - gaim_debug(GAIM_DEBUG_ERROR, "gaim_mkstemp", - "Problem creating the template\n"); - else - { - if( (fp = fopen( result, "w+" )) == NULL ) { - gaim_debug(GAIM_DEBUG_ERROR, "gaim_mkstemp", - "Couldn't fopen() %s\n", result); - } - } -#else - if((fd = mkstemp(*fpath)) == -1) { - gaim_debug(GAIM_DEBUG_ERROR, "gaim_mkstemp", - "Couldn't make \"%s\", error: %d\n", - *fpath, errno); - } else { - if((fp = fdopen(fd, "r+")) == NULL) { - close(fd); - gaim_debug(GAIM_DEBUG_ERROR, "gaim_mkstemp", - "Couldn't fdopen(), error: %d\n", errno); - } - } -#endif - if(!fp) { - g_free(*fpath); - *fpath = NULL; - } - } - } else { - gaim_debug(GAIM_DEBUG_ERROR, "gaim_mkstemp", - "g_get_tmp_dir() failed!"); - } - - return fp; -} - -gboolean program_is_valid(const char *program) -{ - GError *error = NULL; - char **argv; - gchar *progname; - gboolean is_valid = FALSE; - - if (program == NULL || *program == '\0') { - return FALSE; - } - - if (!g_shell_parse_argv(program, NULL, &argv, &error)) { - gaim_debug(GAIM_DEBUG_ERROR, "program_is_valid", - "Could not parse program '%s': %s\n", - program, error->message); - g_error_free(error); - return FALSE; - } - - if (argv == NULL) { - return FALSE; - } - - progname = g_find_program_in_path(argv[0]); - is_valid = (progname != NULL); - - g_strfreev(argv); - g_free(progname); - - return is_valid; -} - -char *gaim_try_conv_to_utf8(const char *str) -{ - gsize converted; - char *utf8; - - if (str == NULL) { - return NULL; - } - - if (g_utf8_validate(str, -1, NULL)) { - return g_strdup(str); - } - - utf8 = g_locale_to_utf8(str, -1, &converted, NULL, NULL); - if (utf8) - return(utf8); - - g_free(utf8); - - utf8 = g_convert(str, -1, "UTF-8", "ISO-8859-15", &converted, NULL, NULL); - if (utf8 && converted == strlen (str)) { - return(utf8); - } else if (utf8) { - g_free(utf8); - } - - return(NULL); -} - -char *gaim_getip_from_fd(int fd) -{ - struct sockaddr addr; - socklen_t namelen = sizeof(addr); - - if (getsockname(fd, &addr, &namelen)) - return NULL; - - return g_strdup(inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr)); -} - -gint gaim_utf8_strcasecmp(const gchar *a, const gchar *b) { - gchar *a_norm=NULL; - gchar *b_norm=NULL; - gint ret=-1; - - if(!a && b) - return -1; - else if(!b && a) - return 1; - else if(!a && !b) - return 0; - - if(!g_utf8_validate(a, -1, NULL) || !g_utf8_validate(b, -1, NULL)) { - gaim_debug(GAIM_DEBUG_ERROR, "gaim_utf8_strcasecmp", "One or both parameters are invalid UTF8\n"); - return ret; - } - - a_norm = g_utf8_casefold(a, -1); - b_norm = g_utf8_casefold(b, -1); - ret = g_utf8_collate(a_norm, b_norm); - g_free(a_norm); - g_free(b_norm); - return ret; -} - -gchar *gaim_strreplace(const gchar *string, const gchar *delimiter, const gchar *replacement) { - gchar **split; - gchar *ret; - - split = g_strsplit(string, delimiter, 0); - ret = g_strjoinv(replacement, split); - g_strfreev(split); - - return ret; -} - -const char *gaim_strcasestr(const char *haystack, const char *needle) { - size_t hlen, nlen; - const char *tmp, *ret; - - g_return_val_if_fail(haystack != NULL, NULL); - g_return_val_if_fail(needle != NULL, NULL); - - hlen = strlen(haystack); - nlen = strlen(needle); - tmp = haystack, - ret = NULL; - - g_return_val_if_fail(hlen > 0, NULL); - g_return_val_if_fail(nlen > 0, NULL); - - while (*tmp && !ret) { - if (!g_ascii_strncasecmp(needle, tmp, nlen)) - ret = tmp; - else - tmp++; - } - - return ret; -} - -char * -gaim_str_size_to_units(size_t size) -{ - static const char *size_str[4] = { "bytes", "KB", "MB", "GB" }; - float size_mag; - int size_index = 0; - - if (size == -1) { - return g_strdup(_("Calculating...")); - } - else if (size == 0) { - return g_strdup(_("Unknown.")); - } - else { - size_mag = (float)size; - - while ((size_index < 4) && (size_mag > 1024)) { - size_mag /= 1024; - size_index++; - } - - return g_strdup_printf("%.2f %s", size_mag, size_str[size_index]); - } -} - +/************************************************************************** + * Markup Functions + **************************************************************************/ gboolean gaim_markup_find_tag(const char *needle, const char *haystack, const char **start, const char **end, GData **attributes) @@ -1386,6 +871,26 @@ return str2; } +static gint +badchar(char c) +{ + switch (c) { + case ' ': + case ',': + case '(': + case ')': + case '\0': + case '\n': + case '<': + case '>': + case '"': + case '\'': + return 1; + default: + return 0; + } +} + char * gaim_markup_linkify(const char *text) { @@ -1595,6 +1100,497 @@ return tmp; } + +/************************************************************************** + * Path/Filename Functions + **************************************************************************/ +const char * +gaim_home_dir(void) +{ +#ifndef _WIN32 + if(g_get_home_dir()) + return g_get_home_dir(); + else + return NULL; +#else + return wgaim_data_dir(); +#endif +} + +/* returns a string of the form ~/.gaim, where ~ is replaced by the user's home + * dir. Note that there is no trailing slash after .gaim. */ +char * +gaim_user_dir(void) +{ + const gchar *hd = gaim_home_dir(); + + if(hd) + { + strcpy( (char*)&home_dir, hd ); + strcat( (char*)&home_dir, G_DIR_SEPARATOR_S ".gaim" ); + + return (gchar*)&home_dir; + } + + return NULL; +} + +/* + * Like mkstemp() but returns a file pointer, uses a pre-set template, + * uses the semantics of tempnam() for the directory to use and allocates + * the space for the filepath. + * + * Caller is responsible for closing the file and removing it when done, + * as well as freeing the space pointed-to by "path" with g_free(). + * + * Returns NULL on failure and cleans up after itself if so. + */ +static const char *gaim_mkstemp_templ = {"gaimXXXXXX"}; + +FILE * +gaim_mkstemp(char **fpath) +{ + const gchar *tmpdir; +#ifndef _WIN32 + int fd; +#endif + FILE *fp = NULL; + + g_return_val_if_fail(fpath != NULL, NULL); + + if((tmpdir = (gchar*)g_get_tmp_dir()) != NULL) { + if((*fpath = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", tmpdir, gaim_mkstemp_templ)) != NULL) { +#ifdef _WIN32 + char* result = _mktemp( *fpath ); + if( result == NULL ) + gaim_debug(GAIM_DEBUG_ERROR, "gaim_mkstemp", + "Problem creating the template\n"); + else + { + if( (fp = fopen( result, "w+" )) == NULL ) { + gaim_debug(GAIM_DEBUG_ERROR, "gaim_mkstemp", + "Couldn't fopen() %s\n", result); + } + } +#else + if((fd = mkstemp(*fpath)) == -1) { + gaim_debug(GAIM_DEBUG_ERROR, "gaim_mkstemp", + "Couldn't make \"%s\", error: %d\n", + *fpath, errno); + } else { + if((fp = fdopen(fd, "r+")) == NULL) { + close(fd); + gaim_debug(GAIM_DEBUG_ERROR, "gaim_mkstemp", + "Couldn't fdopen(), error: %d\n", errno); + } + } +#endif + if(!fp) { + g_free(*fpath); + *fpath = NULL; + } + } + } else { + gaim_debug(GAIM_DEBUG_ERROR, "gaim_mkstemp", + "g_get_tmp_dir() failed!"); + } + + return fp; +} + +gboolean +gaim_program_is_valid(const char *program) +{ + GError *error = NULL; + char **argv; + gchar *progname; + gboolean is_valid = FALSE; + + g_return_val_if_fail(program != NULL, FALSE); + g_return_val_if_fail(*program != '\0', FALSE); + + if (!g_shell_parse_argv(program, NULL, &argv, &error)) { + gaim_debug(GAIM_DEBUG_ERROR, "program_is_valid", + "Could not parse program '%s': %s\n", + program, error->message); + g_error_free(error); + return FALSE; + } + + if (argv == NULL) { + return FALSE; + } + + progname = g_find_program_in_path(argv[0]); + is_valid = (progname != NULL); + + g_strfreev(argv); + g_free(progname); + + return is_valid; +} + +char * +gaim_fd_get_ip(int fd) +{ + struct sockaddr addr; + socklen_t namelen = sizeof(addr); + + g_return_val_if_fail(fd != 0, NULL); + + if (getsockname(fd, &addr, &namelen)) + return NULL; + + return g_strdup(inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr)); +} + + +/************************************************************************** + * String Functions + **************************************************************************/ +char * +gaim_normalize(const char *s) +{ + static char buf[BUF_LEN]; + char *tmp; + int i, j; + + g_return_val_if_fail(s != NULL, NULL); + + strncpy(buf, s, BUF_LEN); + for (i=0, j=0; buf[j]; i++, j++) { + while (buf[j] == ' ') + j++; + buf[i] = buf[j]; + } + buf[i] = '\0'; + + tmp = g_utf8_strdown(buf, -1); + g_snprintf(buf, sizeof(buf), "%s", tmp); + g_free(tmp); + tmp = g_utf8_normalize(buf, -1, G_NORMALIZE_DEFAULT); + g_snprintf(buf, sizeof(buf), "%s", tmp); + g_free(tmp); + + return buf; +} + +/* Look for %n, %d, or %t in msg, and replace with the sender's name, date, + or time */ +char * +gaim_str_sub_away_formatters(const char *msg, const char *name) +{ + char *c; + static char cpy[BUF_LONG]; + int cnt = 0; + time_t t; + struct tm *tme; + char tmp[20]; + + g_return_val_if_fail(msg != NULL, NULL); + g_return_val_if_fail(name != NULL, NULL); + + t = time(NULL); + tme = localtime(&t); + + cpy[0] = '\0'; + c = (char *)msg; + while (*c) { + switch (*c) { + case '%': + if (*(c + 1)) { + switch (*(c + 1)) { + case 'n': + /* append name */ + strcpy(cpy + cnt, name); + cnt += strlen(name); + c++; + break; + case 'd': + /* append date */ + strftime(tmp, 20, "%m/%d/%Y", tme); + strcpy(cpy + cnt, tmp); + cnt += strlen(tmp); + c++; + break; + case 't': + /* append time */ + strftime(tmp, 20, "%r", tme); + strcpy(cpy + cnt, tmp); + cnt += strlen(tmp); + c++; + break; + default: + cpy[cnt++] = *c; + } + } + break; + default: + cpy[cnt++] = *c; + } + c++; + } + cpy[cnt] = '\0'; + return (cpy); +} + +/* + * rcg10312000 This could be more robust, but it works for my current + * goal: to remove those annoying <BR> tags. :) + * dtf12162000 made the loop more readable. i am a neat freak. ;) */ +void +gaim_strncpy_nohtml(char *dest, const char *src, size_t destsize) +{ + char *ptr; + + g_return_if_fail(dest != NULL); + g_return_if_fail(src != NULL); + g_return_if_fail(destsize > 0); + + g_snprintf(dest, destsize, "%s", src); + + while ((ptr = strstr(dest, "<BR>")) != NULL) { + /* replace <BR> with a newline. */ + *ptr = '\n'; + memmove(ptr + 1, ptr + 4, strlen(ptr + 4) + 1); + } +} + +void +gaim_strncpy_withhtml(gchar *dest, const gchar *src, size_t destsize) +{ + gchar *end; + + g_return_if_fail(dest != NULL); + g_return_if_fail(src != NULL); + g_return_if_fail(destsize > 0); + + end = dest + destsize; + + while (dest < end) { + if (*src == '\n' && dest < end - 5) { + strcpy(dest, "<BR>"); + src++; + dest += 4; + } else if(*src == '\r') { + src++; + } else { + *dest++ = *src; + if (*src == '\0') + return; + else + src++; + } + } +} + +/* + * Like strncpy_withhtml (above), but malloc()'s the necessary space + * + * The caller is responsible for freeing the space pointed to by the + * return value. + */ +char * +gaim_strdup_withhtml(const char *src) +{ + char *sp, *dest; + gulong destsize; + + g_return_val_if_fail(src != NULL, NULL); + + /* + * All we need do is multiply the number of newlines by 3 (the + * additional length of "<BR>" over "\n"), account for the + * terminator, malloc the space and call strncpy_withhtml. + */ + for(destsize = 0, sp = (gchar *)src; + (sp = strchr(sp, '\n')) != NULL; + ++sp, ++destsize) + ; + + destsize *= 3; + destsize += strlen(src) + 1; + dest = g_malloc(destsize); + gaim_strncpy_withhtml(dest, src, destsize); + + return dest; +} + +char * +gaim_str_add_cr(const char *text) +{ + char *ret = NULL; + int count = 0, i, j; + + g_return_val_if_fail(text != NULL, NULL); + + if (text[0] == '\n') + count++; + for (i = 1; i < strlen(text); i++) + if (text[i] == '\n' && text[i - 1] != '\r') + count++; + + if (count == 0) + return g_strdup(text); + + ret = g_malloc0(strlen(text) + count + 1); + + i = 0; j = 0; + if (text[i] == '\n') + ret[j++] = '\r'; + ret[j++] = text[i++]; + for (; i < strlen(text); i++) { + if (text[i] == '\n' && text[i - 1] != '\r') + ret[j++] = '\r'; + ret[j++] = text[i]; + } + + gaim_debug_misc("gaim_str_add_cr", "got: %s, leaving with %s\n", + text, ret); + + return ret; +} + +void +gaim_str_strip_linefeed(char *text) +{ + int i, j; + char *text2; + + g_return_if_fail(text != NULL); + + text2 = g_malloc(strlen(text) + 1); + + for (i = 0, j = 0; text[i]; i++) + if (text[i] != '\r') + text2[j++] = text[i]; + text2[j] = '\0'; + + strcpy(text, text2); + g_free(text2); +} + +char * +gaim_strreplace(const char *string, const char *delimiter, + const char *replacement) +{ + gchar **split; + gchar *ret; + + g_return_val_if_fail(string != NULL, NULL); + g_return_val_if_fail(delimiter != NULL, NULL); + g_return_val_if_fail(replacement != NULL, NULL); + + split = g_strsplit(string, delimiter, 0); + ret = g_strjoinv(replacement, split); + g_strfreev(split); + + return ret; +} + +const char * +gaim_strcasestr(const char *haystack, const char *needle) +{ + size_t hlen, nlen; + const char *tmp, *ret; + + g_return_val_if_fail(haystack != NULL, NULL); + g_return_val_if_fail(needle != NULL, NULL); + + hlen = strlen(haystack); + nlen = strlen(needle); + tmp = haystack, + ret = NULL; + + g_return_val_if_fail(hlen > 0, NULL); + g_return_val_if_fail(nlen > 0, NULL); + + while (*tmp && !ret) { + if (!g_ascii_strncasecmp(needle, tmp, nlen)) + ret = tmp; + else + tmp++; + } + + return ret; +} + +char * +gaim_str_size_to_units(size_t size) +{ + static const char *size_str[4] = { "bytes", "KB", "MB", "GB" }; + float size_mag; + int size_index = 0; + + if (size == -1) { + return g_strdup(_("Calculating...")); + } + else if (size == 0) { + return g_strdup(_("Unknown.")); + } + else { + size_mag = (float)size; + + while ((size_index < 4) && (size_mag > 1024)) { + size_mag /= 1024; + size_index++; + } + + return g_strdup_printf("%.2f %s", size_mag, size_str[size_index]); + } +} + +char * +gaim_str_seconds_to_string(guint sec) +{ + guint daze, hrs, min; + char *ret = NULL; + + daze = sec / (60 * 60 * 24); + hrs = (sec % (60 * 60 * 24)) / (60 * 60); + min = (sec % (60 * 60)) / 60; + sec = min % 60; + + if (daze) { + if (hrs || min) { + if (hrs) { + if (min) { + ret = g_strdup_printf( + "%d %s, %d %s, %d %s.", + daze, ngettext("day","days",daze), + hrs, ngettext("hour","hours",hrs), min, ngettext("minute","minutes",min)); + } else { + ret = g_strdup_printf( + "%d %s, %d %s.", + daze, ngettext("day","days",daze), hrs, ngettext("hour","hours",hrs)); + } + } else { + ret = g_strdup_printf( + "%d %s, %d %s.", + daze, ngettext("day","days",daze), min, ngettext("minute","minutes",min)); + } + } else + ret = g_strdup_printf("%d %s.", daze, ngettext("day","days",daze)); + } else { + if (hrs) { + if (min) { + ret = g_strdup_printf( + "%d %s, %d %s.", + hrs, ngettext("hour","hours",hrs), min, ngettext("minute","minutes",min)); + } else { + ret = g_strdup_printf("%d %s.", hrs, ngettext("hour","hours",hrs)); + } + } else { + ret = g_strdup_printf("%d %s.", min, ngettext("minute","minutes",min)); + } + } + + return ret; +} + +/************************************************************************** + * URI/URL Functions + **************************************************************************/ gboolean gaim_url_parse(const char *url, char **ret_host, int *ret_port, char **ret_path) @@ -1920,3 +1916,65 @@ cb(user_data, g_strdup(_("g003: Error opening connection.\n")), 0); } } + + +/************************************************************************** + * UTF8 String Functions + **************************************************************************/ +char * +gaim_utf8_try_convert(const char *str) +{ + gsize converted; + char *utf8; + + g_return_val_if_fail(str != NULL, NULL); + + if (g_utf8_validate(str, -1, NULL)) { + return g_strdup(str); + } + + utf8 = g_locale_to_utf8(str, -1, &converted, NULL, NULL); + if (utf8) + return(utf8); + + g_free(utf8); + + utf8 = g_convert(str, -1, "UTF-8", "ISO-8859-15", &converted, NULL, NULL); + if (utf8 && converted == strlen (str)) { + return(utf8); + } else if (utf8) { + g_free(utf8); + } + + return(NULL); +} + +int +gaim_utf8_strcasecmp(const char *a, const char *b) +{ + char *a_norm = NULL; + char *b_norm = NULL; + int ret = -1; + + if(!a && b) + return -1; + else if(!b && a) + return 1; + else if(!a && !b) + return 0; + + if(!g_utf8_validate(a, -1, NULL) || !g_utf8_validate(b, -1, NULL)) + { + gaim_debug_error("gaim_utf8_strcasecmp", + "One or both parameters are invalid UTF8\n"); + return ret; + } + + a_norm = g_utf8_casefold(a, -1); + b_norm = g_utf8_casefold(b, -1); + ret = g_utf8_collate(a_norm, b_norm); + g_free(a_norm); + g_free(b_norm); + + return ret; +}