aboutsummaryrefslogtreecommitdiff
path: root/src/routines.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/routines.c')
-rw-r--r--src/routines.c800
1 files changed, 800 insertions, 0 deletions
diff --git a/src/routines.c b/src/routines.c
new file mode 100644
index 0000000..8ce937b
--- /dev/null
+++ b/src/routines.c
@@ -0,0 +1,800 @@
+/*
+ * routines.c
+ *
+ * Random Useful Routines and Functions
+ *
+ * (c) 2002-2005 Thomas White <taw27@srcf.ucam.org>
+ * Part of TuxMessenger - GTK+-based MSN Messenger client
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 dated June, 1991.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <glob.h>
+#include <gdk/gdk.h>
+
+#include "debug.h"
+
+char *routines_glob(const char *filename) {
+
+ char *full_filename;
+ glob_t glob_result;
+ int glob_retval;
+
+ glob_retval = glob(filename, GLOB_TILDE, NULL, &glob_result);
+ if ( glob_retval != 0 ) {
+
+ debug_print("glob() failed: ");
+ switch ( glob_retval ) {
+ case GLOB_NOSPACE : debug_print("GLOB_NOSPACE\n"); break;
+ case GLOB_ABORTED : debug_print("GLOB_ABORTED\n"); break;
+ case GLOB_NOMATCH : debug_print("GLOB_NOMATCH\n"); break;
+ default : debug_print("Unknown!\n"); break;
+ }
+ return NULL;
+
+ }
+ full_filename = malloc(strlen(glob_result.gl_pathv[0])+1);
+ strcpy(full_filename, glob_result.gl_pathv[0]);
+ globfree(&glob_result);
+
+ return full_filename;
+
+}
+
+/* TCL-style lindex using ' ' as a separator */
+char *routines_lindex(char *string, unsigned int pos) {
+
+ unsigned int i;
+ unsigned int s=0;
+ char *minibuffer;
+ unsigned int max_output_length = strlen(string);
+ for ( i=0; i<strlen(string); i++ ) {
+
+ if ( string[i] == ' ' )
+ s++;
+ if ( s == pos ) {
+
+ char ch='z';
+ unsigned int p=0;
+ char *result;
+ result = malloc(2+max_output_length);
+ if ( s == 0 )
+ i--;
+ while ((ch != '\0') && (p<max_output_length)) {
+
+ ch = string[i+p+1];
+ if ( ch == ' ' )
+ ch = '\0';
+ if ( ch == '\r' )
+ ch = '\0';
+ if ( ch == '\n' )
+ ch = '\0';
+ result[p]=ch;
+ p++;
+
+ }
+ result[p]='\0';
+
+ /* now copy the string into a buffer that's the right size */
+ minibuffer=malloc(strlen(result)+sizeof(char));
+ strcpy(minibuffer, result);
+ free(result);
+ return minibuffer;
+
+ }
+
+ }
+ /* whoopsie didn't find it */
+ minibuffer = malloc(1);
+ minibuffer[0]='\0';
+ return minibuffer; /* return something that can safely be freed */
+
+}
+
+/* same as above, but returns all of the rest of the string, without stopping at the next space*/
+char *routines_lindexend(char *string, unsigned int pos) {
+
+ unsigned int i;
+ unsigned int s=0;
+ char *minibuffer;
+ unsigned int max_output_length = strlen(string);
+
+ for ( i=0; i<strlen(string); i++ ) {
+ if ( string[i] == ' ' )
+ s++;
+ if ( s == pos ) {
+ char ch='z';
+ unsigned int p=0;
+ char *result;
+ result = malloc(2+max_output_length);
+ if ( s == 0 )
+ i--;
+ while ((ch != '\0') && (p<max_output_length)) {
+ ch = string[i+p+1];
+ if ( ch == '\n' )
+ ch = '\0';
+ if ( ch == '\r' )
+ ch = '\0';
+ result[p]=ch;
+ p++;
+ }
+ result[p]='\0';
+
+ /* now copy the string into a buffer that's the right size */
+ minibuffer=malloc(strlen(result)+sizeof(char));
+ strcpy(minibuffer, result);
+ free(result);
+ return minibuffer;
+ }
+ }
+ /* whoopsie didn't find it */
+ minibuffer = malloc(1);
+ minibuffer[0]='\0';
+ return minibuffer; /* return something that can still be freed */
+
+}
+
+/* Convert a single hex digit char to an int */
+static unsigned int routines_unhex(char ch) {
+
+ switch (ch) {
+ case '0': return 0;
+ case '1': return 1;
+ case '2': return 2;
+ case '3': return 3;
+ case '4': return 4;
+ case '5': return 5;
+ case '6': return 6;
+ case '7': return 7;
+ case '8': return 8;
+ case '9': return 9;
+ case 'a': return 10;
+ case 'b': return 11;
+ case 'c': return 12;
+ case 'd': return 13;
+ case 'e': return 14;
+ case 'f': return 15;
+ case 'A': return 10;
+ case 'B': return 11;
+ case 'C': return 12;
+ case 'D': return 13;
+ case 'E': return 14;
+ case 'F': return 15; /* yes I know i could have done it differently... */
+ }
+
+ return 0; /* clearly this would be the caller's fault... */
+
+}
+
+char *routines_urldecode(const char *words) {
+
+ char *result;
+ char first_char=' ', second_char=' ';
+ unsigned int i, s=0, j=0;
+
+ result = malloc(strlen(words)+1);
+ for ( i=0; i<=strlen(words); i++ ) {
+
+ char ch;
+ ch=words[i];
+
+ if ( isxdigit(ch) && (s==2) ) {
+
+ unsigned int new_ch = 0;
+ unsigned int first_num, second_num;
+ j-=2;
+ second_char=ch;
+
+ /* now we take our two hex digits and decimalize... */
+ first_num = routines_unhex(first_char);
+ second_num = routines_unhex(second_char);
+ new_ch = (char) second_num + (16 * first_num);
+ if ( new_ch == '\0' )
+ new_ch = ' '; /* no way... */
+ if ( new_ch == '\10' )
+ new_ch = ' '; /* f--k off... */
+ if ( new_ch == '\13' )
+ new_ch = ' '; /* grrr */
+
+ ch=new_ch;
+ s=0;
+
+ }
+ if ( isxdigit(ch) && (s==1) ) {
+ s=2;
+ first_char=ch;
+ }
+ if (ch=='%') {
+ s=1;
+ }
+ result[j]=ch;
+ j++;
+
+ }
+ return result;
+
+}
+
+char *routines_urlencode(const char *words) {
+
+ char *result;
+ unsigned int i, p;
+
+ result = malloc((3*strlen(words))+1); /* this is the maximum possible size it could be */
+ p = 0;
+ for ( i=0; i<strlen(words); i++ ) {
+ char ch;
+ ch = words[i];
+ if ( ch == ' ' ) {
+ result[p]='%';
+ p++;
+ result[p]='2';
+ p++;
+ result[p]='0';
+ } else if ( ch == '<' ) {
+ result[p]='%';
+ p++;
+ result[p]='3';
+ p++;
+ result[p]='C';
+ } else if( ch == '>' ) {
+ result[p]='%';
+ p++;
+ result[p]='3';
+ p++;
+ result[p]='E';
+ } else if ( ch == '=' ) {
+ result[p]='%';
+ p++;
+ result[p]='3';
+ p++;
+ result[p]='D';
+ } else if ( ch == '@' ) {
+ result[p]='%';
+ p++;
+ result[p]='4';
+ p++;
+ result[p]='0';
+ } else if ( ch == '\"' ) {
+ result[p]='%';
+ p++;
+ result[p]='2';
+ p++;
+ result[p]='2';
+ } else if ( ch == '/' ) {
+ result[p]='%';
+ p++;
+ result[p]='2';
+ p++;
+ result[p]='F';
+ } else if ( ch == '+' ) {
+ result[p]='%';
+ p++;
+ result[p]='2';
+ p++;
+ result[p]='B';
+ } else {
+ result[p]=ch;
+ }
+ p++;
+ }
+ result[p]='\0';
+ return result;
+}
+
+/* extract hostname from hostname:port style string */
+char *routines_hostname(const char *input) {
+
+ unsigned int i, n=0;
+ char ch='z';
+ char *output;
+
+ /* First we must check that there is actually a colon present */
+ for ( i=0; i<strlen(input); i++ ) {
+ if ( input[i] == ':' ) {
+ n++;
+ }
+ }
+ /* if there's no colon, host is just the same as the input */
+ if ( n == 0 )
+ return strdup(input);
+
+ i = 0;
+ /* A few bytes get wasted here */
+ output = malloc(strlen(input));
+ while ( ch != '\0' ) {
+
+ ch = input[i];
+ if ( ch == ':' ) {
+ ch = '\0';
+ }
+ output[i] = ch;
+ i++;
+
+ }
+ return output;
+ /* You can free the output string when you've finished with it */
+
+}
+
+/* extract the port number from hostname:port */
+int routines_port(const char *input) {
+
+ char ch='z';
+ unsigned int i=0, n=0;
+
+ /* first we must check that there is actually a colon present */
+ for ( i=0; i<strlen(input); i++ ) {
+ if ( input[i] == ':' )
+ n++;
+ }
+ /* Bail out if no port specified */
+ if ( n == 0 ) {
+ return 0;
+ }
+
+ i=0;
+ while ( (ch != ':') && (i<=strlen(input)) ) {
+ ch = input[i];
+ i++;
+ }
+
+ return atoi(input+i);
+}
+
+static char routines_base64char(unsigned int sextet) {
+
+ switch (sextet) {
+
+ case 0 : return 'A';
+ case 1 : return 'B';
+ case 2 : return 'C';
+ case 3 : return 'D';
+ case 4 : return 'E';
+ case 5 : return 'F';
+ case 6 : return 'G';
+ case 7 : return 'H';
+ case 8 : return 'I';
+ case 9 : return 'J';
+ case 10 : return 'K';
+ case 11 : return 'L';
+ case 12 : return 'M';
+ case 13 : return 'N';
+ case 14 : return 'O';
+ case 15 : return 'P';
+ case 16 : return 'Q';
+ case 17 : return 'R';
+ case 18 : return 'S';
+ case 19 : return 'T';
+ case 20 : return 'U';
+ case 21 : return 'V';
+ case 22 : return 'W';
+ case 23 : return 'X';
+ case 24 : return 'Y';
+ case 25 : return 'Z';
+ case 26 : return 'a';
+ case 27 : return 'b';
+ case 28 : return 'c';
+ case 29 : return 'd';
+ case 30 : return 'e';
+ case 31 : return 'f';
+ case 32 : return 'g';
+ case 33 : return 'h';
+ case 34 : return 'i';
+ case 35 : return 'j';
+ case 36 : return 'k';
+ case 37 : return 'l';
+ case 38 : return 'm';
+ case 39 : return 'n';
+ case 40 : return 'o';
+ case 41 : return 'p';
+ case 42 : return 'q';
+ case 43 : return 'r';
+ case 44 : return 's';
+ case 45 : return 't';
+ case 46 : return 'u';
+ case 47 : return 'v';
+ case 48 : return 'w';
+ case 49 : return 'x';
+ case 50 : return 'y';
+ case 51 : return 'z';
+ case 52 : return '0';
+ case 53 : return '1';
+ case 54 : return '2';
+ case 55 : return '3';
+ case 56 : return '4';
+ case 57 : return '5';
+ case 58 : return '6';
+ case 59 : return '7';
+ case 60 : return '8';
+ case 61 : return '9';
+ case 62 : return '+';
+ case 63 : return '/';
+
+ }
+
+ return 'A';
+
+}
+
+static int routines_unbase64char(unsigned char sextet) {
+
+ switch (sextet) {
+
+ case 'A' : return 0;
+ case 'B' : return 1;
+ case 'C' : return 2;
+ case 'D' : return 3;
+ case 'E' : return 4;
+ case 'F' : return 5;
+ case 'G' : return 6;
+ case 'H' : return 7;
+ case 'I' : return 8;
+ case 'J' : return 9;
+ case 'K' : return 10;
+ case 'L' : return 11;
+ case 'M' : return 12;
+ case 'N' : return 13;
+ case 'O' : return 14;
+ case 'P' : return 15;
+ case 'Q' : return 16;
+ case 'R' : return 17;
+ case 'S' : return 18;
+ case 'T' : return 19;
+ case 'U' : return 20;
+ case 'V' : return 21;
+ case 'W' : return 22;
+ case 'X' : return 23;
+ case 'Y' : return 24;
+ case 'Z' : return 25;
+ case 'a' : return 26;
+ case 'b' : return 27;
+ case 'c' : return 28;
+ case 'd' : return 29;
+ case 'e' : return 30;
+ case 'f' : return 31;
+ case 'g' : return 32;
+ case 'h' : return 33;
+ case 'i' : return 34;
+ case 'j' : return 35;
+ case 'k' : return 36;
+ case 'l' : return 37;
+ case 'm' : return 38;
+ case 'n' : return 39;
+ case 'o' : return 40;
+ case 'p' : return 41;
+ case 'q' : return 42;
+ case 'r' : return 43;
+ case 's' : return 44;
+ case 't' : return 45;
+ case 'u' : return 46;
+ case 'v' : return 47;
+ case 'w' : return 48;
+ case 'x' : return 49;
+ case 'y' : return 50;
+ case 'z' : return 51;
+ case '0' : return 52;
+ case '1' : return 53;
+ case '2' : return 54;
+ case '3' : return 55;
+ case '4' : return 56;
+ case '5' : return 57;
+ case '6' : return 58;
+ case '7' : return 59;
+ case '8' : return 60;
+ case '9' : return 61;
+ case '+' : return 62;
+ case '/' : return 63;
+
+ }
+
+ return 0;
+
+}
+
+char *routines_base64givenlength(char *base64_input, ssize_t length) {
+
+ ssize_t i;
+ char *base64_output;
+ unsigned int sextet;
+ size_t j = 0;
+
+ /* One extra byte for \0 terminator, another for rounding error. */
+ base64_output = malloc((4*length)/3 + 4);
+
+ for ( i=0; i<=length-3; i+=3 ) {
+
+ /* First sextet */
+ sextet = (base64_input[i] & 0xfc) >> 2;
+ base64_output[j++] = routines_base64char(sextet);
+
+ /* Second sextet */
+ sextet = ((base64_input[i] & 0x3) << 4) + ((base64_input[i+1] & 0xf0) >> 4);
+ base64_output[j++] = routines_base64char(sextet);
+
+ /* Third sextet */
+ sextet = ((base64_input[i+1] & 0x0f) << 2) + ((base64_input[i+2] & 0xc0) >> 6);
+ base64_output[j++] = routines_base64char(sextet);
+
+ /* Fourth sextet */
+ sextet = (base64_input[i+2] & 0x3f);
+ base64_output[j++] = routines_base64char(sextet);
+
+ }
+
+ switch ((length) % 3) {
+
+ case 1 : {
+
+ /* One byte left over */
+ i = length-1;
+
+ sextet = (base64_input[i] & 0xfc) >> 2;
+ base64_output[j++] = routines_base64char(sextet);
+
+ sextet = (base64_input[i] & 0x03) << 4;
+ base64_output[j++] = routines_base64char(sextet);
+
+ base64_output[j++] = '=';
+ base64_output[j++] = '=';
+
+ break;
+
+ }
+
+ case 2 : {
+
+ /* Two bytes left over */
+ i = length-2;
+
+ sextet = (base64_input[i] & 0xfc) >> 2;
+ base64_output[j++] = routines_base64char(sextet);
+
+ sextet = ((base64_input[i] & 0x3) << 4) + ((base64_input[i+1] & 0xf0) >> 4);
+ base64_output[j++] = routines_base64char(sextet);
+
+ sextet = (base64_input[i+1] & 0x0f) << 2;
+ base64_output[j++] = routines_base64char(sextet);
+
+ base64_output[j++] = '=';
+
+ break;
+
+ }
+
+ }
+
+ base64_output[j++] = '\0';
+
+ return base64_output;
+
+}
+
+/* Base64-encode something. Needs to have a NULL terminator. */
+char *routines_base64(char *base64_input) {
+ return routines_base64givenlength(base64_input, strlen(base64_input)+1);
+}
+
+/* Decode Base64 string (with terminator) and put pointer to result at "output". Return length of result. */
+size_t routines_base64decode(const char *base64_input, char **output) {
+
+ size_t len = 0;
+ size_t ptr = 0;
+ char *op = malloc(strlen(base64_input));
+
+ assert(strlen(base64_input) % 4 == 0 );
+
+ while ( ptr < strlen(base64_input) ) {
+
+ op[len] = (routines_unbase64char(base64_input[ptr]) << 2) + ((routines_unbase64char(base64_input[ptr+1]) & 48) >> 4);
+ op[len+1] = ((routines_unbase64char(base64_input[ptr+1]) & 15) << 4) + ((routines_unbase64char(base64_input[ptr+2]) & 60) >> 2);
+ op[len+2] = ((routines_unbase64char(base64_input[ptr+2]) & 3) << 6) + routines_unbase64char(base64_input[ptr+3]);
+
+ len+=3;
+ ptr+=4;
+
+ }
+
+ if ( base64_input[ptr-1] == '=' ) {
+ len--;
+ }
+ if ( base64_input[ptr-2] == '=' ) {
+ len--;
+ }
+
+ *output = op;
+ return len;
+
+}
+
+static char *routines_randomhexbyte() {
+
+ int j;
+ char *response = malloc(3);
+
+ /* Taken from the "rand()" man page. */
+ j = 1 +(int)(256.0*rand()/(RAND_MAX+1.0));
+ sprintf(response, "%2hhx", j);
+
+ return response;
+
+}
+
+/* Generate a GUID */
+char *routines_guid() {
+
+ int i, k;
+ char *guid;
+
+ guid = malloc(39);
+ assert(guid != NULL);
+ strcpy(guid, "{");
+
+ for ( i=0; i<4; i++ ) {
+
+ char *byte;
+ byte = routines_randomhexbyte();
+ strncat(guid, byte, 2);
+ free(byte);
+
+ }
+
+ for ( k=0; k<3; k++ ) {
+
+ strcat(guid, "-");
+ for ( i=0; i<2; i++ ) {
+
+ char *byte;
+ byte = routines_randomhexbyte();
+ strncat(guid, byte, 2);
+ free(byte);
+
+ }
+
+ }
+
+ /* To be a valid GUID, the version and variant fields need to be set appropriately. */
+ guid[15] = '4';
+ guid[20] = 'a';
+
+ strcat(guid, "-");
+ for ( i=0; i<6; i++ ) {
+
+ char *byte;
+ byte = routines_randomhexbyte();
+ strncat(guid, byte, 2);
+ free(byte);
+
+ }
+ strcat(guid, "}");
+
+ /* Fix up spaces. */
+ for ( i=0; i<(strlen(guid)-1); i++ ) {
+ if ( guid[i] == ' ' ) {
+ guid[i] = '0';
+ }
+ }
+
+ return guid;
+
+}
+
+/* Replace triangular brackets with something Pango can handle. */
+char *routines_killtriangles(const char *input) {
+
+ char *output;
+ size_t i;
+ size_t j = 0;
+
+ output = malloc(2*strlen(input)+1);
+ for ( i=0; i<=strlen(input); i++ ) {
+ if ( input[i] == '<' ) {
+ output[j] = '&'; j++;
+ output[j] = 'l'; j++;
+ output[j] = 't'; j++;
+ output[j] = ';'; j++;
+ } else if ( input[i] == '>' ) {
+ output[j] = '&'; j++;
+ output[j] = 'g'; j++;
+ output[j] = 't'; j++;
+ output[j] = ';'; j++;
+ } else {
+ output[j] = input[i]; j++;
+ }
+ }
+
+ return output;
+
+}
+
+/* Replace triangular brackets and ampersands with something Pango can handle. */
+char *routines_killtriangles_and_ampersands(const char *input) {
+
+ char *output;
+ size_t i;
+ size_t j = 0;
+
+ output = malloc(2*strlen(input)+1);
+ for ( i=0; i<=strlen(input); i++ ) {
+ if ( input[i] == '<' ) {
+ output[j] = '&'; j++;
+ output[j] = 'l'; j++;
+ output[j] = 't'; j++;
+ output[j] = ';'; j++;
+ } else if ( input[i] == '>' ) {
+ output[j] = '&'; j++;
+ output[j] = 'g'; j++;
+ output[j] = 't'; j++;
+ output[j] = ';'; j++;
+ } else if ( input[i] == '&' ) {
+ output[j] = '&'; j++;
+ output[j] = 'a'; j++;
+ output[j] = 'm'; j++;
+ output[j] = 'p'; j++;
+ output[j] = ';'; j++;
+ } else {
+ output[j] = input[i]; j++;
+ }
+ }
+
+ return output;
+
+}
+
+char *routines_flipcolour(const char *colour) {
+
+ char *flipped = malloc(7);
+ char scratch;
+ strncpy(flipped, colour, 6);
+ flipped[6] = '\0';
+
+ scratch = flipped[0];
+ flipped[0] = flipped[4];
+ flipped[4] = scratch;
+
+ scratch = flipped[1];
+ flipped[1] = flipped[5];
+ flipped[5] = scratch;
+
+ return flipped;
+
+}
+
+char *routines_gdk_to_hashrgb(const GdkColor *colour) {
+
+ char *string;
+
+ if ( colour == NULL ) {
+ return NULL;
+ }
+
+ string = malloc(8);
+ /* RGB order */
+ snprintf(string, 8, "#%02hhx%02hhx%02hhx", colour->red >> 8, colour->green >> 8, colour->blue >> 8);
+ string[7] = '\0';
+
+ return string;
+
+}