configure: add stuff for spell checking
[rofl0r-ixchat.git] / src / common / util.c
blob220613b0654ea81137675d58332c1c1f0f4c2316
1 /* X-Chat
2 * Copyright (C) 1998 Peter Zelezny.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 #define __APPLE_API_STRICT_CONFORMANCE
21 #define _FILE_OFFSET_BITS 64
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <pwd.h>
30 #include <sys/time.h>
31 #include <sys/utsname.h>
32 #include <fcntl.h>
33 #include <dirent.h>
34 #include <errno.h>
35 #include "xchat.h"
36 #include "xchatc.h"
37 #include <glib.h>
38 #include <ctype.h>
39 #include "util.h"
41 #define WANTSOCKET
42 #include "inet.h"
44 #if defined (USING_FREEBSD) || defined (__APPLE__)
45 #include <sys/sysctl.h>
46 #endif
47 #ifdef SOCKS
48 #include <socks.h>
49 #endif
51 #ifdef USE_DEBUG
53 #undef free
54 #undef malloc
55 #undef realloc
56 #undef strdup
58 int current_mem_usage;
60 struct mem_block
62 char *file;
63 void *buf;
64 int size;
65 int line;
66 int total;
67 struct mem_block *next;
70 struct mem_block *mroot = NULL;
72 void *
73 xchat_malloc (int size, char *file, int line)
75 void *ret;
76 struct mem_block *new;
78 current_mem_usage += size;
79 ret = malloc (size);
80 if (!ret)
82 printf ("Out of memory! (%d)\n", current_mem_usage);
83 exit (255);
86 new = malloc (sizeof (struct mem_block));
87 new->buf = ret;
88 new->size = size;
89 new->next = mroot;
90 new->line = line;
91 new->file = strdup (file);
92 mroot = new;
94 printf ("%s:%d Malloc'ed %d bytes, now \033[35m%d\033[m\n", file, line,
95 size, current_mem_usage);
97 return ret;
100 void *
101 xchat_realloc (char *old, int len, char *file, int line)
103 char *ret;
105 ret = xchat_malloc (len, file, line);
106 if (ret)
108 strcpy (ret, old);
109 xchat_dfree (old, file, line);
111 return ret;
114 void *
115 xchat_strdup (char *str, char *file, int line)
117 void *ret;
118 struct mem_block *new;
119 int size;
121 size = strlen (str) + 1;
122 current_mem_usage += size;
123 ret = malloc (size);
124 if (!ret)
126 printf ("Out of memory! (%d)\n", current_mem_usage);
127 exit (255);
129 strcpy (ret, str);
131 new = malloc (sizeof (struct mem_block));
132 new->buf = ret;
133 new->size = size;
134 new->next = mroot;
135 new->line = line;
136 new->file = strdup (file);
137 mroot = new;
139 printf ("%s:%d strdup (\"%-.40s\") size: %d, total: \033[35m%d\033[m\n",
140 file, line, str, size, current_mem_usage);
142 return ret;
145 void
146 xchat_mem_list (void)
148 struct mem_block *cur, *p;
149 GSList *totals = 0;
150 GSList *list;
152 cur = mroot;
153 while (cur)
155 list = totals;
156 while (list)
158 p = list->data;
159 if (p->line == cur->line &&
160 strcmp (p->file, cur->file) == 0)
162 p->total += p->size;
163 break;
165 list = list->next;
167 if (!list)
169 cur->total = cur->size;
170 totals = g_slist_prepend (totals, cur);
172 cur = cur->next;
175 fprintf (stderr, "file line size num total\n");
176 list = totals;
177 while (list)
179 cur = list->data;
180 fprintf (stderr, "%-15.15s %6d %6d %6d %6d\n", cur->file, cur->line,
181 cur->size, cur->total/cur->size, cur->total);
182 list = list->next;
186 void
187 xchat_dfree (void *buf, char *file, int line)
189 struct mem_block *cur, *last;
191 if (buf == NULL)
193 printf ("%s:%d \033[33mTried to free NULL\033[m\n", file, line);
194 return;
197 last = NULL;
198 cur = mroot;
199 while (cur)
201 if (buf == cur->buf)
202 break;
203 last = cur;
204 cur = cur->next;
206 if (cur == NULL)
208 printf ("%s:%d \033[31mTried to free unknown block %lx!\033[m\n",
209 file, line, (unsigned long) buf);
210 /* abort(); */
211 free (buf);
212 return;
214 current_mem_usage -= cur->size;
215 printf ("%s:%d Free'ed %d bytes, usage now \033[35m%d\033[m\n",
216 file, line, cur->size, current_mem_usage);
217 if (last)
218 last->next = cur->next;
219 else
220 mroot = cur->next;
221 free (cur->file);
222 free (cur);
225 #define malloc(n) xchat_malloc(n, __FILE__, __LINE__)
226 #define realloc(n, m) xchat_realloc(n, m, __FILE__, __LINE__)
227 #define free(n) xchat_dfree(n, __FILE__, __LINE__)
228 #define strdup(n) xchat_strdup(n, __FILE__, __LINE__)
230 #endif /* MEMORY_DEBUG */
232 char *
233 file_part (char *file)
235 char *filepart = file;
236 if (!file)
237 return "";
238 while (1)
240 switch (*file)
242 case 0:
243 return (filepart);
244 case '/':
245 #ifdef WIN32
246 case '\\':
247 #endif
248 filepart = file + 1;
249 break;
251 file++;
255 void
256 path_part (char *file, char *path, int pathlen)
258 unsigned char t;
259 char *filepart = file_part (file);
260 t = *filepart;
261 *filepart = 0;
262 safe_strcpy (path, file, pathlen);
263 *filepart = t;
266 char * /* like strstr(), but nocase */
267 nocasestrstr (const char *s, const char *wanted)
269 register const int len = strlen (wanted);
271 if (len == 0)
272 return (char *)s;
273 while (rfc_tolower(*s) != rfc_tolower(*wanted) || strncasecmp (s, wanted, len))
274 if (*s++ == '\0')
275 return (char *)NULL;
276 return (char *)s;
279 char *
280 errorstring (int err)
282 switch (err)
284 case -1:
285 return "";
286 case 0:
287 return _("Remote host closed socket");
288 #ifndef WIN32
290 #else
291 case WSAECONNREFUSED:
292 return _("Connection refused");
293 case WSAENETUNREACH:
294 case WSAEHOSTUNREACH:
295 return _("No route to host");
296 case WSAETIMEDOUT:
297 return _("Connection timed out");
298 case WSAEADDRNOTAVAIL:
299 return _("Cannot assign that address");
300 case WSAECONNRESET:
301 return _("Connection reset by peer");
304 /* can't use strerror() on Winsock errors! */
305 if (err >= WSABASEERR)
307 static char tbuf[384];
308 OSVERSIONINFO osvi;
310 osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
311 GetVersionEx (&osvi);
313 /* FormatMessage works on WSA*** errors starting from Win2000 */
314 if (osvi.dwMajorVersion >= 5)
316 if (FormatMessageA (FORMAT_MESSAGE_FROM_SYSTEM |
317 FORMAT_MESSAGE_IGNORE_INSERTS |
318 FORMAT_MESSAGE_MAX_WIDTH_MASK,
319 NULL, err,
320 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
321 tbuf, sizeof (tbuf), NULL))
323 int len;
324 char *utf;
326 tbuf[sizeof (tbuf) - 1] = 0;
327 len = strlen (tbuf);
328 if (len >= 2)
329 tbuf[len - 2] = 0; /* remove the cr-lf */
331 /* now convert to utf8 */
332 utf = g_locale_to_utf8 (tbuf, -1, 0, 0, 0);
333 if (utf)
335 safe_strcpy (tbuf, utf, sizeof (tbuf));
336 g_free (utf);
337 return tbuf;
340 } /* ! if (osvi.dwMajorVersion >= 5) */
342 /* fallback to error number */
343 sprintf (tbuf, "%s %d", _("Error"), err);
344 return tbuf;
345 } /* ! if (err >= WSABASEERR) */
346 #endif /* ! WIN32 */
348 return strerror (err);
352 waitline (int sok, char *buf, int bufsize, int use_recv)
354 int i = 0;
356 while (1)
358 if (use_recv)
360 if (recv (sok, &buf[i], 1, 0) < 1)
361 return -1;
362 } else
364 if (read (sok, &buf[i], 1) < 1)
365 return -1;
367 if (buf[i] == '\n' || bufsize == i + 1)
369 buf[i] = 0;
370 return i;
372 i++;
376 /* checks for "~" in a file and expands */
378 char *
379 expand_homedir (char *file)
381 #ifndef WIN32
382 char *ret, *user;
383 struct passwd *pw;
385 if (*file == '~')
387 if (file[1] != '\0' && file[1] != '/')
389 user = strdup(file);
390 if (strchr(user,'/') != NULL)
391 *(strchr(user,'/')) = '\0';
392 if ((pw = getpwnam(user + 1)) == NULL)
394 free(user);
395 return strdup(file);
397 free(user);
398 user = strchr(file, '/') != NULL ? strchr(file,'/') : file;
399 ret = malloc(strlen(user) + strlen(pw->pw_dir) + 1);
400 strcpy(ret, pw->pw_dir);
401 strcat(ret, user);
403 else
405 ret = malloc (strlen (file) + strlen (g_get_home_dir ()) + 1);
406 sprintf (ret, "%s%s", g_get_home_dir (), file + 1);
408 return ret;
410 #endif
411 return strdup (file);
414 gchar *
415 strip_color (const char *text, int len, int flags)
417 char *new_str;
419 if (len == -1)
420 len = strlen (text);
422 new_str = g_malloc (len + 2);
423 strip_color2 (text, len, new_str, flags);
425 if (flags & STRIP_ESCMARKUP)
427 char *esc = g_markup_escape_text (new_str, -1);
428 g_free (new_str);
429 return esc;
432 return new_str;
435 /* CL: strip_color2 strips src and writes the output at dst; pass the same pointer
436 in both arguments to strip in place. */
438 strip_color2 (const char *src, int len, char *dst, int flags)
440 int rcol = 0, bgcol = 0;
441 char *start = dst;
443 if (len == -1) len = strlen (src);
444 while (len-- > 0)
446 if (rcol > 0 && (isdigit ((unsigned char)*src) ||
447 (*src == ',' && isdigit ((unsigned char)src[1]) && !bgcol)))
449 if (src[1] != ',') rcol--;
450 if (*src == ',')
452 rcol = 2;
453 bgcol = 1;
455 } else
457 rcol = bgcol = 0;
458 switch (*src)
460 case '\003': /*ATTR_COLOR: */
461 if (!(flags & STRIP_COLOR)) goto pass_char;
462 rcol = 2;
463 break;
464 case HIDDEN_CHAR: /* CL: invisible text (for event formats only) */ /* this takes care of the topic */
465 if (!(flags & STRIP_HIDDEN)) goto pass_char;
466 break;
467 case '\007': /*ATTR_BEEP: */
468 case '\017': /*ATTR_RESET: */
469 case '\026': /*ATTR_REVERSE: */
470 case '\002': /*ATTR_BOLD: */
471 case '\037': /*ATTR_UNDERLINE: */
472 case '\035': /*ATTR_ITALICS: */
473 if (!(flags & STRIP_ATTRIB)) goto pass_char;
474 break;
475 default:
476 pass_char:
477 *dst++ = *src;
480 src++;
482 *dst = 0;
484 return (int) (dst - start);
488 strip_hidden_attribute (char *src, char *dst)
490 int len = 0;
491 while (*src != '\000')
493 if (*src != HIDDEN_CHAR)
495 *dst++ = *src;
496 len++;
498 src++;
500 return len;
503 #if defined (USING_LINUX) || defined (USING_FREEBSD) || defined (__APPLE__)
505 static void
506 get_cpu_info (double *mhz, int *cpus)
509 #ifdef USING_LINUX
511 char buf[256];
512 int fh;
514 *mhz = 0;
515 *cpus = 0;
517 fh = open ("/proc/cpuinfo", O_RDONLY); /* linux 2.2+ only */
518 if (fh == -1)
520 *cpus = 1;
521 return;
524 while (1)
526 if (waitline (fh, buf, sizeof buf, FALSE) < 0)
527 break;
528 if (!strncmp (buf, "cycle frequency [Hz]\t:", 22)) /* alpha */
530 *mhz = atoi (buf + 23) / 1000000;
531 } else if (!strncmp (buf, "cpu MHz\t\t:", 10)) /* i386 */
533 *mhz = atof (buf + 11) + 0.5;
534 } else if (!strncmp (buf, "clock\t\t:", 8)) /* PPC */
536 *mhz = atoi (buf + 9);
537 } else if (!strncmp (buf, "processor\t", 10))
539 (*cpus)++;
542 close (fh);
543 if (!*cpus)
544 *cpus = 1;
546 #endif
547 #ifdef USING_FREEBSD
549 int mib[2], ncpu;
550 u_long freq;
551 size_t len;
553 freq = 0;
554 *mhz = 0;
555 *cpus = 0;
557 mib[0] = CTL_HW;
558 mib[1] = HW_NCPU;
560 len = sizeof(ncpu);
561 sysctl(mib, 2, &ncpu, &len, NULL, 0);
563 len = sizeof(freq);
564 sysctlbyname("machdep.tsc_freq", &freq, &len, NULL, 0);
566 *cpus = ncpu;
567 *mhz = (freq / 1000000);
569 #endif
570 #ifdef __APPLE__
572 int mib[2], ncpu;
573 unsigned long long freq;
574 size_t len;
576 freq = 0;
577 *mhz = 0;
578 *cpus = 0;
580 mib[0] = CTL_HW;
581 mib[1] = HW_NCPU;
583 len = sizeof(ncpu);
584 sysctl(mib, 2, &ncpu, &len, NULL, 0);
586 len = sizeof(freq);
587 sysctlbyname("hw.cpufrequency", &freq, &len, NULL, 0);
589 *cpus = ncpu;
590 *mhz = (freq / 1000000);
592 #endif
595 #endif
597 #ifdef WIN32
599 static int
600 get_mhz (void)
602 HKEY hKey;
603 int result, data, dataSize;
605 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Hardware\\Description\\System\\"
606 "CentralProcessor\\0", 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
608 dataSize = sizeof (data);
609 result = RegQueryValueEx (hKey, "~MHz", 0, 0, (LPBYTE)&data, &dataSize);
610 RegCloseKey (hKey);
611 if (result == ERROR_SUCCESS)
612 return data;
614 return 0; /* fails on Win9x */
617 char *
618 get_cpu_str (void)
620 static char verbuf[64];
621 OSVERSIONINFO osvi;
622 SYSTEM_INFO si;
623 double mhz;
625 osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
626 GetVersionEx (&osvi);
627 GetSystemInfo (&si);
629 mhz = get_mhz ();
630 if (mhz)
632 double cpuspeed = ( mhz > 1000 ) ? mhz / 1000 : mhz;
633 const char *cpuspeedstr = ( mhz > 1000 ) ? "GHz" : "MHz";
634 sprintf (verbuf, "Windows %ld.%ld [i%d86/%.2f%s]",
635 osvi.dwMajorVersion, osvi.dwMinorVersion, si.wProcessorLevel,
636 cpuspeed, cpuspeedstr);
637 } else
638 sprintf (verbuf, "Windows %ld.%ld [i%d86]",
639 osvi.dwMajorVersion, osvi.dwMinorVersion, si.wProcessorLevel);
641 return verbuf;
644 #else
646 char *
647 get_cpu_str (void)
649 #if defined (USING_LINUX) || defined (USING_FREEBSD) || defined (__APPLE__)
650 double mhz;
651 #endif
652 int cpus = 1;
653 struct utsname un;
654 static char *buf = NULL;
656 if (buf)
657 return buf;
659 buf = malloc (128);
661 uname (&un);
663 #if defined (USING_LINUX) || defined (USING_FREEBSD) || defined (__APPLE__)
664 get_cpu_info (&mhz, &cpus);
665 if (mhz)
667 double cpuspeed = ( mhz > 1000 ) ? mhz / 1000 : mhz;
668 const char *cpuspeedstr = ( mhz > 1000 ) ? "GHz" : "MHz";
669 snprintf (buf, 128,
670 (cpus == 1) ? "%s %s [%s/%.2f%s]" : "%s %s [%s/%.2f%s/SMP]",
671 un.sysname, un.release, un.machine,
672 cpuspeed, cpuspeedstr);
673 } else
674 #endif
675 snprintf (buf, 128,
676 (cpus == 1) ? "%s %s [%s]" : "%s %s [%s/SMP]",
677 un.sysname, un.release, un.machine);
679 return buf;
682 #endif
685 buf_get_line (char *ibuf, char **buf, int *position, int len)
687 int pos = *position, spos = pos;
689 if (pos == len)
690 return 0;
692 while (ibuf[pos++] != '\n')
694 if (pos == len)
695 return 0;
697 pos--;
698 ibuf[pos] = 0;
699 *buf = &ibuf[spos];
700 pos++;
701 *position = pos;
702 return 1;
705 int match(const char *mask, const char *string)
707 register const char *m = mask, *s = string;
708 register char ch;
709 const char *bm, *bs; /* Will be reg anyway on a decent CPU/compiler */
711 /* Process the "head" of the mask, if any */
712 while ((ch = *m++) && (ch != '*'))
713 switch (ch)
715 case '\\':
716 if (*m == '?' || *m == '*')
717 ch = *m++;
718 default:
719 if (rfc_tolower(*s) != rfc_tolower(ch))
720 return 0;
721 case '?':
722 if (!*s++)
723 return 0;
725 if (!ch)
726 return !(*s);
728 /* We got a star: quickly find if/where we match the next char */
729 got_star:
730 bm = m; /* Next try rollback here */
731 while ((ch = *m++))
732 switch (ch)
734 case '?':
735 if (!*s++)
736 return 0;
737 case '*':
738 bm = m;
739 continue; /* while */
740 case '\\':
741 if (*m == '?' || *m == '*')
742 ch = *m++;
743 default:
744 goto break_while; /* C is structured ? */
746 break_while:
747 if (!ch)
748 return 1; /* mask ends with '*', we got it */
749 ch = rfc_tolower(ch);
750 while (rfc_tolower(*s++) != ch)
751 if (!*s)
752 return 0;
753 bs = s; /* Next try start from here */
755 /* Check the rest of the "chunk" */
756 while ((ch = *m++))
758 switch (ch)
760 case '*':
761 goto got_star;
762 case '\\':
763 if (*m == '?' || *m == '*')
764 ch = *m++;
765 default:
766 if (rfc_tolower(*s) != rfc_tolower(ch))
768 if (!*s)
769 return 0;
770 m = bm;
771 s = bs;
772 goto got_star;
774 case '?':
775 if (!*s++)
776 return 0;
779 if (*s)
781 m = bm;
782 s = bs;
783 goto got_star;
785 return 1;
788 void
789 for_files (char *dirname, char *mask, void callback (char *file))
791 DIR *dir;
792 struct dirent *ent;
793 char *buf;
795 dir = opendir (dirname);
796 if (dir)
798 while ((ent = readdir (dir)))
800 if (strcmp (ent->d_name, ".") && strcmp (ent->d_name, ".."))
802 if (match (mask, ent->d_name))
804 buf = malloc (strlen (dirname) + strlen (ent->d_name) + 2);
805 sprintf (buf, "%s/%s", dirname, ent->d_name);
806 callback (buf);
807 free (buf);
811 closedir (dir);
815 /*void
816 tolowerStr (char *str)
818 while (*str)
820 *str = rfc_tolower (*str);
821 str++;
825 typedef struct
827 char *code, *country;
828 } domain_t;
830 static int
831 country_compare (const void *a, const void *b)
833 return strcasecmp (a, ((domain_t *)b)->code);
836 static const domain_t domain[] =
838 {"AC", N_("Ascension Island") },
839 {"AD", N_("Andorra") },
840 {"AE", N_("United Arab Emirates") },
841 {"AF", N_("Afghanistan") },
842 {"AG", N_("Antigua and Barbuda") },
843 {"AI", N_("Anguilla") },
844 {"AL", N_("Albania") },
845 {"AM", N_("Armenia") },
846 {"AN", N_("Netherlands Antilles") },
847 {"AO", N_("Angola") },
848 {"AQ", N_("Antarctica") },
849 {"AR", N_("Argentina") },
850 {"ARPA", N_("Reverse DNS") },
851 {"AS", N_("American Samoa") },
852 {"AT", N_("Austria") },
853 {"ATO", N_("Nato Fiel") },
854 {"AU", N_("Australia") },
855 {"AW", N_("Aruba") },
856 {"AX", N_("Aland Islands") },
857 {"AZ", N_("Azerbaijan") },
858 {"BA", N_("Bosnia and Herzegovina") },
859 {"BB", N_("Barbados") },
860 {"BD", N_("Bangladesh") },
861 {"BE", N_("Belgium") },
862 {"BF", N_("Burkina Faso") },
863 {"BG", N_("Bulgaria") },
864 {"BH", N_("Bahrain") },
865 {"BI", N_("Burundi") },
866 {"BIZ", N_("Businesses"), },
867 {"BJ", N_("Benin") },
868 {"BM", N_("Bermuda") },
869 {"BN", N_("Brunei Darussalam") },
870 {"BO", N_("Bolivia") },
871 {"BR", N_("Brazil") },
872 {"BS", N_("Bahamas") },
873 {"BT", N_("Bhutan") },
874 {"BV", N_("Bouvet Island") },
875 {"BW", N_("Botswana") },
876 {"BY", N_("Belarus") },
877 {"BZ", N_("Belize") },
878 {"CA", N_("Canada") },
879 {"CC", N_("Cocos Islands") },
880 {"CD", N_("Democratic Republic of Congo") },
881 {"CF", N_("Central African Republic") },
882 {"CG", N_("Congo") },
883 {"CH", N_("Switzerland") },
884 {"CI", N_("Cote d'Ivoire") },
885 {"CK", N_("Cook Islands") },
886 {"CL", N_("Chile") },
887 {"CM", N_("Cameroon") },
888 {"CN", N_("China") },
889 {"CO", N_("Colombia") },
890 {"COM", N_("Internic Commercial") },
891 {"CR", N_("Costa Rica") },
892 {"CS", N_("Serbia and Montenegro") },
893 {"CU", N_("Cuba") },
894 {"CV", N_("Cape Verde") },
895 {"CX", N_("Christmas Island") },
896 {"CY", N_("Cyprus") },
897 {"CZ", N_("Czech Republic") },
898 {"DE", N_("Germany") },
899 {"DJ", N_("Djibouti") },
900 {"DK", N_("Denmark") },
901 {"DM", N_("Dominica") },
902 {"DO", N_("Dominican Republic") },
903 {"DZ", N_("Algeria") },
904 {"EC", N_("Ecuador") },
905 {"EDU", N_("Educational Institution") },
906 {"EE", N_("Estonia") },
907 {"EG", N_("Egypt") },
908 {"EH", N_("Western Sahara") },
909 {"ER", N_("Eritrea") },
910 {"ES", N_("Spain") },
911 {"ET", N_("Ethiopia") },
912 {"EU", N_("European Union") },
913 {"FI", N_("Finland") },
914 {"FJ", N_("Fiji") },
915 {"FK", N_("Falkland Islands") },
916 {"FM", N_("Micronesia") },
917 {"FO", N_("Faroe Islands") },
918 {"FR", N_("France") },
919 {"GA", N_("Gabon") },
920 {"GB", N_("Great Britain") },
921 {"GD", N_("Grenada") },
922 {"GE", N_("Georgia") },
923 {"GF", N_("French Guiana") },
924 {"GG", N_("British Channel Isles") },
925 {"GH", N_("Ghana") },
926 {"GI", N_("Gibraltar") },
927 {"GL", N_("Greenland") },
928 {"GM", N_("Gambia") },
929 {"GN", N_("Guinea") },
930 {"GOV", N_("Government") },
931 {"GP", N_("Guadeloupe") },
932 {"GQ", N_("Equatorial Guinea") },
933 {"GR", N_("Greece") },
934 {"GS", N_("S. Georgia and S. Sandwich Isles") },
935 {"GT", N_("Guatemala") },
936 {"GU", N_("Guam") },
937 {"GW", N_("Guinea-Bissau") },
938 {"GY", N_("Guyana") },
939 {"HK", N_("Hong Kong") },
940 {"HM", N_("Heard and McDonald Islands") },
941 {"HN", N_("Honduras") },
942 {"HR", N_("Croatia") },
943 {"HT", N_("Haiti") },
944 {"HU", N_("Hungary") },
945 {"ID", N_("Indonesia") },
946 {"IE", N_("Ireland") },
947 {"IL", N_("Israel") },
948 {"IM", N_("Isle of Man") },
949 {"IN", N_("India") },
950 {"INFO", N_("Informational") },
951 {"INT", N_("International") },
952 {"IO", N_("British Indian Ocean Territory") },
953 {"IQ", N_("Iraq") },
954 {"IR", N_("Iran") },
955 {"IS", N_("Iceland") },
956 {"IT", N_("Italy") },
957 {"JE", N_("Jersey") },
958 {"JM", N_("Jamaica") },
959 {"JO", N_("Jordan") },
960 {"JP", N_("Japan") },
961 {"KE", N_("Kenya") },
962 {"KG", N_("Kyrgyzstan") },
963 {"KH", N_("Cambodia") },
964 {"KI", N_("Kiribati") },
965 {"KM", N_("Comoros") },
966 {"KN", N_("St. Kitts and Nevis") },
967 {"KP", N_("North Korea") },
968 {"KR", N_("South Korea") },
969 {"KW", N_("Kuwait") },
970 {"KY", N_("Cayman Islands") },
971 {"KZ", N_("Kazakhstan") },
972 {"LA", N_("Laos") },
973 {"LB", N_("Lebanon") },
974 {"LC", N_("Saint Lucia") },
975 {"LI", N_("Liechtenstein") },
976 {"LK", N_("Sri Lanka") },
977 {"LR", N_("Liberia") },
978 {"LS", N_("Lesotho") },
979 {"LT", N_("Lithuania") },
980 {"LU", N_("Luxembourg") },
981 {"LV", N_("Latvia") },
982 {"LY", N_("Libya") },
983 {"MA", N_("Morocco") },
984 {"MC", N_("Monaco") },
985 {"MD", N_("Moldova") },
986 {"MED", N_("United States Medical") },
987 {"MG", N_("Madagascar") },
988 {"MH", N_("Marshall Islands") },
989 {"MIL", N_("Military") },
990 {"MK", N_("Macedonia") },
991 {"ML", N_("Mali") },
992 {"MM", N_("Myanmar") },
993 {"MN", N_("Mongolia") },
994 {"MO", N_("Macau") },
995 {"MP", N_("Northern Mariana Islands") },
996 {"MQ", N_("Martinique") },
997 {"MR", N_("Mauritania") },
998 {"MS", N_("Montserrat") },
999 {"MT", N_("Malta") },
1000 {"MU", N_("Mauritius") },
1001 {"MV", N_("Maldives") },
1002 {"MW", N_("Malawi") },
1003 {"MX", N_("Mexico") },
1004 {"MY", N_("Malaysia") },
1005 {"MZ", N_("Mozambique") },
1006 {"NA", N_("Namibia") },
1007 {"NC", N_("New Caledonia") },
1008 {"NE", N_("Niger") },
1009 {"NET", N_("Internic Network") },
1010 {"NF", N_("Norfolk Island") },
1011 {"NG", N_("Nigeria") },
1012 {"NI", N_("Nicaragua") },
1013 {"NL", N_("Netherlands") },
1014 {"NO", N_("Norway") },
1015 {"NP", N_("Nepal") },
1016 {"NR", N_("Nauru") },
1017 {"NU", N_("Niue") },
1018 {"NZ", N_("New Zealand") },
1019 {"OM", N_("Oman") },
1020 {"ORG", N_("Internic Non-Profit Organization") },
1021 {"PA", N_("Panama") },
1022 {"PE", N_("Peru") },
1023 {"PF", N_("French Polynesia") },
1024 {"PG", N_("Papua New Guinea") },
1025 {"PH", N_("Philippines") },
1026 {"PK", N_("Pakistan") },
1027 {"PL", N_("Poland") },
1028 {"PM", N_("St. Pierre and Miquelon") },
1029 {"PN", N_("Pitcairn") },
1030 {"PR", N_("Puerto Rico") },
1031 {"PS", N_("Palestinian Territory") },
1032 {"PT", N_("Portugal") },
1033 {"PW", N_("Palau") },
1034 {"PY", N_("Paraguay") },
1035 {"QA", N_("Qatar") },
1036 {"RE", N_("Reunion") },
1037 {"RO", N_("Romania") },
1038 {"RPA", N_("Old School ARPAnet") },
1039 {"RU", N_("Russian Federation") },
1040 {"RW", N_("Rwanda") },
1041 {"SA", N_("Saudi Arabia") },
1042 {"SB", N_("Solomon Islands") },
1043 {"SC", N_("Seychelles") },
1044 {"SD", N_("Sudan") },
1045 {"SE", N_("Sweden") },
1046 {"SG", N_("Singapore") },
1047 {"SH", N_("St. Helena") },
1048 {"SI", N_("Slovenia") },
1049 {"SJ", N_("Svalbard and Jan Mayen Islands") },
1050 {"SK", N_("Slovak Republic") },
1051 {"SL", N_("Sierra Leone") },
1052 {"SM", N_("San Marino") },
1053 {"SN", N_("Senegal") },
1054 {"SO", N_("Somalia") },
1055 {"SR", N_("Suriname") },
1056 {"ST", N_("Sao Tome and Principe") },
1057 {"SU", N_("Former USSR") },
1058 {"SV", N_("El Salvador") },
1059 {"SY", N_("Syria") },
1060 {"SZ", N_("Swaziland") },
1061 {"TC", N_("Turks and Caicos Islands") },
1062 {"TD", N_("Chad") },
1063 {"TF", N_("French Southern Territories") },
1064 {"TG", N_("Togo") },
1065 {"TH", N_("Thailand") },
1066 {"TJ", N_("Tajikistan") },
1067 {"TK", N_("Tokelau") },
1068 {"TL", N_("East Timor") },
1069 {"TM", N_("Turkmenistan") },
1070 {"TN", N_("Tunisia") },
1071 {"TO", N_("Tonga") },
1072 {"TP", N_("East Timor") },
1073 {"TR", N_("Turkey") },
1074 {"TT", N_("Trinidad and Tobago") },
1075 {"TV", N_("Tuvalu") },
1076 {"TW", N_("Taiwan") },
1077 {"TZ", N_("Tanzania") },
1078 {"UA", N_("Ukraine") },
1079 {"UG", N_("Uganda") },
1080 {"UK", N_("United Kingdom") },
1081 {"US", N_("United States of America") },
1082 {"UY", N_("Uruguay") },
1083 {"UZ", N_("Uzbekistan") },
1084 {"VA", N_("Vatican City State") },
1085 {"VC", N_("St. Vincent and the Grenadines") },
1086 {"VE", N_("Venezuela") },
1087 {"VG", N_("British Virgin Islands") },
1088 {"VI", N_("US Virgin Islands") },
1089 {"VN", N_("Vietnam") },
1090 {"VU", N_("Vanuatu") },
1091 {"WF", N_("Wallis and Futuna Islands") },
1092 {"WS", N_("Samoa") },
1093 {"YE", N_("Yemen") },
1094 {"YT", N_("Mayotte") },
1095 {"YU", N_("Yugoslavia") },
1096 {"ZA", N_("South Africa") },
1097 {"ZM", N_("Zambia") },
1098 {"ZW", N_("Zimbabwe") },
1101 char *
1102 country (char *hostname)
1104 char *p;
1105 domain_t *dom;
1107 if (!hostname || !*hostname || isdigit ((unsigned char) hostname[strlen (hostname) - 1]))
1108 return _("Unknown");
1109 if ((p = strrchr (hostname, '.')))
1110 p++;
1111 else
1112 p = hostname;
1114 dom = bsearch (p, domain, sizeof (domain) / sizeof (domain_t),
1115 sizeof (domain_t), country_compare);
1117 if (!dom)
1118 return _("Unknown");
1120 return _(dom->country);
1123 void
1124 country_search (char *pattern, void *ud, void (*print)(void *, char *, ...))
1126 const domain_t *dom;
1127 int i;
1129 for (i = 0; i < sizeof (domain) / sizeof (domain_t); i++)
1131 dom = &domain[i];
1132 if (match (pattern, dom->country) || match (pattern, _(dom->country)))
1134 print (ud, "%s = %s\n", dom->code, _(dom->country));
1139 /* I think gnome1.0.x isn't necessarily linked against popt, ah well! */
1140 /* !!! For now use this inlined function, or it would break fe-text building */
1141 /* .... will find a better solution later. */
1142 /*#ifndef USE_GNOME*/
1144 /* this is taken from gnome-libs 1.2.4 */
1145 #define POPT_ARGV_ARRAY_GROW_DELTA 5
1147 int my_poptParseArgvString(const char * s, int * argcPtr, char *** argvPtr) {
1148 char * buf, * bufStart, * dst;
1149 const char * src;
1150 char quote = '\0';
1151 int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA;
1152 char ** argv = malloc(sizeof(*argv) * argvAlloced);
1153 const char ** argv2;
1154 int argc = 0;
1155 int i, buflen;
1157 buflen = strlen(s) + 1;
1158 /* bufStart = buf = alloca(buflen);*/
1159 bufStart = buf = malloc (buflen);
1160 memset(buf, '\0', buflen);
1162 src = s;
1163 argv[argc] = buf;
1165 while (*src) {
1166 if (quote == *src) {
1167 quote = '\0';
1168 } else if (quote) {
1169 if (*src == '\\') {
1170 src++;
1171 if (!*src) {
1172 free(argv);
1173 free(bufStart);
1174 return 1;
1176 if (*src != quote) *buf++ = '\\';
1178 *buf++ = *src;
1179 /*} else if (isspace((unsigned char) *src)) {*/
1180 } else if (*src == ' ') {
1181 if (*argv[argc]) {
1182 buf++, argc++;
1183 if (argc == argvAlloced) {
1184 argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA;
1185 argv = realloc(argv, sizeof(*argv) * argvAlloced);
1187 argv[argc] = buf;
1189 } else switch (*src) {
1190 case '"':
1191 case '\'':
1192 quote = *src;
1193 break;
1194 case '\\':
1195 src++;
1196 if (!*src) {
1197 free(argv);
1198 free(bufStart);
1199 return 1;
1201 /* fallthrough */
1202 default:
1203 *buf++ = *src;
1206 src++;
1209 if (strlen(argv[argc])) {
1210 argc++, buf++;
1213 dst = malloc((argc + 1) * sizeof(*argv) + (buf - bufStart));
1214 argv2 = (void *) dst;
1215 dst += (argc + 1) * sizeof(*argv);
1216 memcpy((void *)argv2, argv, argc * sizeof(*argv));
1217 argv2[argc] = NULL;
1218 memcpy(dst, bufStart, buf - bufStart);
1220 for (i = 0; i < argc; i++) {
1221 argv2[i] = dst + (argv[i] - bufStart);
1224 free(argv);
1226 *argvPtr = (char **)argv2; /* XXX don't change the API */
1227 *argcPtr = argc;
1229 free (bufStart);
1231 return 0;
1235 util_exec (const char *cmd)
1237 int pid;
1238 char **argv;
1239 int argc;
1240 int fd;
1242 if (my_poptParseArgvString (cmd, &argc, &argv) != 0)
1243 return -1;
1245 #ifndef WIN32
1246 pid = fork ();
1247 if (pid == -1)
1248 return -1;
1249 if (pid == 0)
1251 /* Now close all open file descriptors except stdin, stdout and stderr */
1252 for (fd = 3; fd < 1024; fd++) close(fd);
1253 execvp (argv[0], argv);
1254 _exit (0);
1255 } else
1257 free (argv);
1258 return pid;
1260 #else
1261 spawnvp (_P_DETACH, argv[0], argv);
1262 free (argv);
1263 return 0;
1264 #endif
1268 util_execv (char * const argv[])
1270 int pid, fd;
1272 #ifndef WIN32
1273 pid = fork ();
1274 if (pid == -1)
1275 return -1;
1276 if (pid == 0)
1278 /* Now close all open file descriptors except stdin, stdout and stderr */
1279 for (fd = 3; fd < 1024; fd++) close(fd);
1280 execv (argv[0], argv);
1281 _exit (0);
1282 } else
1284 return pid;
1286 #else
1287 spawnv (_P_DETACH, argv[0], argv);
1288 return 0;
1289 #endif
1292 unsigned long
1293 make_ping_time (void)
1295 #ifndef WIN32
1296 struct timeval timev;
1297 gettimeofday (&timev, 0);
1298 #else
1299 GTimeVal timev;
1300 g_get_current_time (&timev);
1301 #endif
1302 return (timev.tv_sec - 50000) * 1000000 + timev.tv_usec;
1306 /************************************************************************
1307 * This technique was borrowed in part from the source code to
1308 * ircd-hybrid-5.3 to implement case-insensitive string matches which
1309 * are fully compliant with Section 2.2 of RFC 1459, the copyright
1310 * of that code being (C) 1990 Jarkko Oikarinen and under the GPL.
1312 * A special thanks goes to Mr. Okarinen for being the one person who
1313 * seems to have ever noticed this section in the original RFC and
1314 * written code for it. Shame on all the rest of you (myself included).
1316 * --+ Dagmar d'Surreal
1320 rfc_casecmp (const char *s1, const char *s2)
1322 register unsigned char *str1 = (unsigned char *) s1;
1323 register unsigned char *str2 = (unsigned char *) s2;
1324 register int res;
1326 while ((res = rfc_tolower (*str1) - rfc_tolower (*str2)) == 0)
1328 if (*str1 == '\0')
1329 return 0;
1330 str1++;
1331 str2++;
1333 return (res);
1337 rfc_ncasecmp (char *str1, char *str2, int n)
1339 register unsigned char *s1 = (unsigned char *) str1;
1340 register unsigned char *s2 = (unsigned char *) str2;
1341 register int res;
1343 while ((res = rfc_tolower (*s1) - rfc_tolower (*s2)) == 0)
1345 s1++;
1346 s2++;
1347 n--;
1348 if (n == 0 || (*s1 == '\0' && *s2 == '\0'))
1349 return 0;
1351 return (res);
1354 const unsigned char rfc_tolowertab[] =
1355 { 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
1356 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
1357 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
1358 0x1e, 0x1f,
1359 ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
1360 '*', '+', ',', '-', '.', '/',
1361 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1362 ':', ';', '<', '=', '>', '?',
1363 '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
1364 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
1365 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
1366 '_',
1367 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
1368 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
1369 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
1370 0x7f,
1371 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
1372 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
1373 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
1374 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
1375 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
1376 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
1377 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
1378 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
1379 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
1380 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
1381 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
1382 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
1383 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
1384 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
1385 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
1386 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
1389 /*static unsigned char touppertab[] =
1390 { 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
1391 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
1392 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
1393 0x1e, 0x1f,
1394 ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
1395 '*', '+', ',', '-', '.', '/',
1396 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1397 ':', ';', '<', '=', '>', '?',
1398 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
1399 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
1400 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^',
1401 0x5f,
1402 '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
1403 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
1404 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^',
1405 0x7f,
1406 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
1407 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
1408 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
1409 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
1410 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
1411 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
1412 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
1413 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
1414 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
1415 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
1416 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
1417 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
1418 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
1419 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
1420 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
1421 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
1422 };*/
1424 /*static int
1425 rename_utf8 (char *oldname, char *newname)
1427 int sav, res;
1428 char *fso, *fsn;
1430 fso = xchat_filename_from_utf8 (oldname, -1, 0, 0, 0);
1431 if (!fso)
1432 return FALSE;
1433 fsn = xchat_filename_from_utf8 (newname, -1, 0, 0, 0);
1434 if (!fsn)
1436 g_free (fso);
1437 return FALSE;
1440 res = rename (fso, fsn);
1441 sav = errno;
1442 g_free (fso);
1443 g_free (fsn);
1444 errno = sav;
1445 return res;
1448 static int
1449 unlink_utf8 (char *fname)
1451 int res;
1452 char *fs;
1454 fs = xchat_filename_from_utf8 (fname, -1, 0, 0, 0);
1455 if (!fs)
1456 return FALSE;
1458 res = unlink (fs);
1459 g_free (fs);
1460 return res;
1463 static gboolean
1464 file_exists_utf8 (char *fname)
1466 int res;
1467 char *fs;
1469 fs = xchat_filename_from_utf8 (fname, -1, 0, 0, 0);
1470 if (!fs)
1471 return FALSE;
1473 res = access (fs, F_OK);
1474 g_free (fs);
1475 if (res == 0)
1476 return TRUE;
1477 return FALSE;
1480 static gboolean
1481 copy_file (char *dl_src, char *dl_dest, int permissions) /* FS encoding */
1483 int tmp_src, tmp_dest;
1484 gboolean ok = FALSE;
1485 char dl_tmp[4096];
1486 int return_tmp, return_tmp2;
1488 if ((tmp_src = open (dl_src, O_RDONLY | OFLAGS)) == -1)
1490 fprintf (stderr, "Unable to open() file '%s' (%s) !", dl_src,
1491 strerror (errno));
1492 return FALSE;
1495 if ((tmp_dest =
1496 open (dl_dest, O_WRONLY | O_CREAT | O_TRUNC | OFLAGS, permissions)) < 0)
1498 close (tmp_src);
1499 fprintf (stderr, "Unable to create file '%s' (%s) !", dl_src,
1500 strerror (errno));
1501 return FALSE;
1504 for (;;)
1506 return_tmp = read (tmp_src, dl_tmp, sizeof (dl_tmp));
1508 if (!return_tmp)
1510 ok = TRUE;
1511 break;
1514 if (return_tmp < 0)
1516 fprintf (stderr, "download_move_to_completed_dir(): "
1517 "error reading while moving file to save directory (%s)",
1518 strerror (errno));
1519 break;
1522 return_tmp2 = write (tmp_dest, dl_tmp, return_tmp);
1524 if (return_tmp2 < 0)
1526 fprintf (stderr, "download_move_to_completed_dir(): "
1527 "error writing while moving file to save directory (%s)",
1528 strerror (errno));
1529 break;
1532 if (return_tmp < sizeof (dl_tmp))
1534 ok = TRUE;
1535 break;
1539 close (tmp_dest);
1540 close (tmp_src);
1541 return ok;
1544 /* Takes care of moving a file from a temporary download location to a completed location. Now in UTF-8. */
1545 void
1546 move_file_utf8 (char *src_dir, char *dst_dir, char *fname, int dccpermissions)
1548 char src[4096];
1549 char dst[4096];
1550 int res, i;
1551 char *src_fs; /* FileSystem encoding */
1552 char *dst_fs;
1554 /* if dcc_dir and dcc_completed_dir are the same then we are done */
1555 if (0 == strcmp (src_dir, dst_dir) ||
1556 0 == dst_dir[0])
1557 return; /* Already in "completed dir" */
1559 snprintf (src, sizeof (src), "%s/%s", src_dir, fname);
1560 snprintf (dst, sizeof (dst), "%s/%s", dst_dir, fname);
1562 /* already exists in completed dir? Append a number */
1563 if (file_exists_utf8 (dst))
1565 for (i = 0; ; i++)
1567 snprintf (dst, sizeof (dst), "%s/%s.%d", dst_dir, fname, i);
1568 if (!file_exists_utf8 (dst))
1569 break;
1573 /* convert UTF-8 to filesystem encoding */
1574 src_fs = xchat_filename_from_utf8 (src, -1, 0, 0, 0);
1575 if (!src_fs)
1576 return;
1577 dst_fs = xchat_filename_from_utf8 (dst, -1, 0, 0, 0);
1578 if (!dst_fs)
1580 g_free (src_fs);
1581 return;
1584 /* first try a simple rename move */
1585 res = rename (src_fs, dst_fs);
1587 if (res == -1 && (errno == EXDEV || errno == EPERM))
1589 /* link failed because either the two paths aren't on the */
1590 /* same filesystem or the filesystem doesn't support hard */
1591 /* links, so we have to do a copy. */
1592 if (copy_file (src_fs, dst_fs, dccpermissions))
1593 unlink (src_fs);
1596 g_free (dst_fs);
1597 g_free (src_fs);
1601 mkdir_utf8 (char *dir)
1603 int ret;
1605 dir = xchat_filename_from_utf8 (dir, -1, 0, 0, 0);
1606 if (!dir)
1607 return -1;
1609 #ifdef WIN32
1610 ret = mkdir (dir);
1611 #else
1612 ret = mkdir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
1613 #endif
1614 g_free (dir);
1616 return ret;
1619 /* separates a string according to a 'sep' char, then calls the callback
1620 function for each token found */
1623 token_foreach (char *str, char sep,
1624 int (*callback) (char *str, void *ud), void *ud)
1626 char t, *start = str;
1628 while (1)
1630 if (*str == sep || *str == 0)
1632 t = *str;
1633 *str = 0;
1634 if (callback (start, ud) < 1)
1636 *str = t;
1637 return FALSE;
1639 *str = t;
1641 if (*str == 0)
1642 break;
1643 str++;
1644 start = str;
1646 } else
1648 /* chars $00-$7f can never be embedded in utf-8 */
1649 str++;
1653 return TRUE;
1656 /* 31 bit string hash functions */
1658 guint32
1659 str_hash (const char *key)
1661 const char *p = key;
1662 guint32 h = *p;
1664 if (h)
1665 for (p += 1; *p != '\0'; p++)
1666 h = (h << 5) - h + *p;
1668 return h;
1671 guint32
1672 str_ihash (const unsigned char *key)
1674 const char *p = key;
1675 guint32 h = rfc_tolowertab [(guint)*p];
1677 if (h)
1678 for (p += 1; *p != '\0'; p++)
1679 h = (h << 5) - h + rfc_tolowertab [(guint)*p];
1681 return h;
1684 /* features: 1. "src" must be valid, NULL terminated UTF-8 */
1685 /* 2. "dest" will be left with valid UTF-8 - no partial chars! */
1687 void
1688 safe_strcpy (char *dest, const char *src, int bytes_left)
1690 int mbl;
1692 while (1)
1694 mbl = g_utf8_skip[*((unsigned char *)src)];
1696 if (bytes_left < (mbl + 1)) /* can't fit with NULL? */
1698 *dest = 0;
1699 break;
1702 if (mbl == 1) /* one byte char */
1704 *dest = *src;
1705 if (*src == 0)
1706 break; /* it all fit */
1707 dest++;
1708 src++;
1709 bytes_left--;
1711 else /* multibyte char */
1713 memcpy (dest, src, mbl);
1714 dest += mbl;
1715 src += mbl;
1716 bytes_left -= mbl;