/* X-Chat * Copyright (C) 1998 Peter Zelezny. * * This program 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; either version 2 of the License, or * (at your option) any later version. * * This program 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 program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #define WANTSOCKET #include "inet.h" /* make it first to avoid macro redefinitions */ #define __APPLE_API_STRICT_CONFORMANCE #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #ifdef WIN32 #include #include #include #include "../dirent/dirent-win32.h" #else #include #include #include #include #include #endif #include #include #include "xchat.h" #include "xchatc.h" #include #include #include "util.h" #include "../../config.h" #if defined (USING_FREEBSD) || defined (__APPLE__) #include #endif #ifdef SOCKS #include #endif #ifndef HAVE_SNPRINTF #define snprintf g_snprintf #endif #ifdef USE_DEBUG #undef free #undef malloc #undef realloc #undef strdup int current_mem_usage; struct mem_block { char *file; void *buf; int size; int line; int total; struct mem_block *next; }; struct mem_block *mroot = NULL; void * xchat_malloc (int size, char *file, int line) { void *ret; struct mem_block *new; current_mem_usage += size; ret = malloc (size); if (!ret) { printf ("Out of memory! (%d)\n", current_mem_usage); exit (255); } new = malloc (sizeof (struct mem_block)); new->buf = ret; new->size = size; new->next = mroot; new->line = line; new->file = strdup (file); mroot = new; printf ("%s:%d Malloc'ed %d bytes, now \033[35m%d\033[m\n", file, line, size, current_mem_usage); return ret; } void * xchat_realloc (char *old, int len, char *file, int line) { char *ret; ret = xchat_malloc (len, file, line); if (ret) { strcpy (ret, old); xchat_dfree (old, file, line); } return ret; } void * xchat_strdup (char *str, char *file, int line) { void *ret; struct mem_block *new; int size; size = strlen (str) + 1; current_mem_usage += size; ret = malloc (size); if (!ret) { printf ("Out of memory! (%d)\n", current_mem_usage); exit (255); } strcpy (ret, str); new = malloc (sizeof (struct mem_block)); new->buf = ret; new->size = size; new->next = mroot; new->line = line; new->file = strdup (file); mroot = new; printf ("%s:%d strdup (\"%-.40s\") size: %d, total: \033[35m%d\033[m\n", file, line, str, size, current_mem_usage); return ret; } void xchat_mem_list (void) { struct mem_block *cur, *p; GSList *totals = 0; GSList *list; cur = mroot; while (cur) { list = totals; while (list) { p = list->data; if (p->line == cur->line && strcmp (p->file, cur->file) == 0) { p->total += p->size; break; } list = list->next; } if (!list) { cur->total = cur->size; totals = g_slist_prepend (totals, cur); } cur = cur->next; } fprintf (stderr, "file line size num total\n"); list = totals; while (list) { cur = list->data; fprintf (stderr, "%-15.15s %6d %6d %6d %6d\n", cur->file, cur->line, cur->size, cur->total/cur->size, cur->total); list = list->next; } } void xchat_dfree (void *buf, char *file, int line) { struct mem_block *cur, *last; if (buf == NULL) { printf ("%s:%d \033[33mTried to free NULL\033[m\n", file, line); return; } last = NULL; cur = mroot; while (cur) { if (buf == cur->buf) break; last = cur; cur = cur->next; } if (cur == NULL) { printf ("%s:%d \033[31mTried to free unknown block %lx!\033[m\n", file, line, (unsigned long) buf); /* abort(); */ free (buf); return; } current_mem_usage -= cur->size; printf ("%s:%d Free'ed %d bytes, usage now \033[35m%d\033[m\n", file, line, cur->size, current_mem_usage); if (last) last->next = cur->next; else mroot = cur->next; free (cur->file); free (cur); } #define malloc(n) xchat_malloc(n, __FILE__, __LINE__) #define realloc(n, m) xchat_realloc(n, m, __FILE__, __LINE__) #define free(n) xchat_dfree(n, __FILE__, __LINE__) #define strdup(n) xchat_strdup(n, __FILE__, __LINE__) #endif /* MEMORY_DEBUG */ char * file_part (char *file) { char *filepart = file; if (!file) return ""; while (1) { switch (*file) { case 0: return (filepart); case '/': #ifdef WIN32 case '\\': #endif filepart = file + 1; break; } file++; } } void path_part (char *file, char *path, int pathlen) { unsigned char t; char *filepart = file_part (file); t = *filepart; *filepart = 0; safe_strcpy (path, file, pathlen); *filepart = t; } char * /* like strstr(), but nocase */ nocasestrstr (const char *s, const char *wanted) { register const int len = strlen (wanted); if (len == 0) return (char *)s; while (rfc_tolower(*s) != rfc_tolower(*wanted) || g_ascii_strncasecmp (s, wanted, len)) if (*s++ == '\0') return (char *)NULL; return (char *)s; } char * errorstring (int err) { switch (err) { case -1: return ""; case 0: return _("Remote host closed socket"); #ifndef WIN32 } #else case WSAECONNREFUSED: return _("Connection refused"); case WSAENETUNREACH: case WSAEHOSTUNREACH: return _("No route to host"); case WSAETIMEDOUT: return _("Connection timed out"); case WSAEADDRNOTAVAIL: return _("Cannot assign that address"); case WSAECONNRESET: return _("Connection reset by peer"); } /* can't use strerror() on Winsock errors! */ if (err >= WSABASEERR) { static char tbuf[384]; OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); GetVersionEx (&osvi); /* FormatMessage works on WSA*** errors starting from Win2000 */ if (osvi.dwMajorVersion >= 5) { if (FormatMessageA (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, err, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), tbuf, sizeof (tbuf), NULL)) { int len; char *utf; tbuf[sizeof (tbuf) - 1] = 0; len = strlen (tbuf); if (len >= 2) tbuf[len - 2] = 0; /* remove the cr-lf */ /* now convert to utf8 */ utf = g_locale_to_utf8 (tbuf, -1, 0, 0, 0); if (utf) { safe_strcpy (tbuf, utf, sizeof (tbuf)); g_free (utf); return tbuf; } } } /* ! if (osvi.dwMajorVersion >= 5) */ /* fallback to error number */ sprintf (tbuf, "%s %d", _("Error"), err); return tbuf; } /* ! if (err >= WSABASEERR) */ #endif /* ! WIN32 */ return strerror (err); } int waitline (int sok, char *buf, int bufsize, int use_recv) { int i = 0; while (1) { if (use_recv) { if (recv (sok, &buf[i], 1, 0) < 1) return -1; } else { if (read (sok, &buf[i], 1) < 1) return -1; } if (buf[i] == '\n' || bufsize == i + 1) { buf[i] = 0; return i; } i++; } } #ifdef WIN32 /* waitline2 using win32 file descriptor and glib instead of _read. win32 can't _read() sok! */ int waitline2 (GIOChannel *s
/*
 * @file libsexy/sexy-spell-entry.h Entry widget
 *
 * @Copyright (C) 2004-2006 Christian Hammond.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA  02111-1307, USA.
 */
#ifndef _SEXY_SPELL_ENTRY_H_
#define _SEXY_SPELL_ENTRY_H_

typedef struct _SexySpellEntry      SexySpellEntry;
typedef struct _SexySpellEntryClass SexySpellEntryClass;
typedef struct _SexySpellEntryPriv  SexySpellEntryPriv;

#include <gtk/gtkentry.h>

#define SEXY_TYPE_SPELL_ENTRY            (sexy_spell_entry_get_type())
#define SEXY_SPELL_ENTRY(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), SEXY_TYPE_SPELL_ENTRY, SexySpellEntry))
#define SEXY_SPELL_ENTRY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), SEXY_TYPE_SPELL_ENTRY, SexySpellEntryClass))
#define SEXY_IS_SPELL_ENTRY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), SEXY_TYPE_SPELL_ENTRY))
#define SEXY_IS_SPELL_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SEXY_TYPE_SPELL_ENTRY))
#define SEXY_SPELL_ENTRY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), SEXY_TYPE_SPELL_ENTRY, SexySpellEntryClass))

#define SEXY_SPELL_ERROR                 (sexy_spell_error_quark())

typedef enum {
	SEXY_SPELL_ERROR_BACKEND,
} SexySpellError;

struct _SexySpellEntry
{
	GtkEntry parent_object;

	SexySpellEntryPriv *priv;

	void (*gtk_reserved1)(void);
	void (*gtk_reserved2)(void);
	void (*gtk_reserved3)(void);
	void (*gtk_reserved4)(void);
};

struct _SexySpellEntryClass
{
	GtkEntryClass parent_class;

	/* Signals */
	gboolean (*word_check)(SexySpellEntry *entry, const gchar *word);

	void (*gtk_reserved1)(void);
	void (*gtk_reserved2)(void);
	void (*gtk_reserved3)(void);
	void (*gtk_reserved4)(void);
};

G_BEGIN_DECLS

GType      sexy_spell_entry_get_type(void);
GtkWidget *sexy_spell_entry_new(void);
GQuark     sexy_spell_error_quark(void);

GSList    *sexy_spell_entry_get_languages(const SexySpellEntry *entry);
gchar     *sexy_spell_entry_get_language_name(const SexySpellEntry *entry, const gchar *lang);
gboolean   sexy_spell_entry_language_is_active(const SexySpellEntry *entry, const gchar *lang);
gboolean   sexy_spell_entry_activate_language(SexySpellEntry *entry, const gchar *lang, GError **error);
void       sexy_spell_entry_deactivate_language(SexySpellEntry *entry, const gchar *lang);
gboolean   sexy_spell_entry_set_active_languages(SexySpellEntry *entry, GSList *langs, GError **error);
GSList    *sexy_spell_entry_get_active_languages(SexySpellEntry *entry);
gboolean   sexy_spell_entry_is_checked(SexySpellEntry *entry);
void       sexy_spell_entry_set_checked(SexySpellEntry *entry, gboolean checked);
void       sexy_spell_entry_activate_default_languages(SexySpellEntry *entry);

G_END_DECLS

#endif
Ukraine") }, {"UG", N_("Uganda") }, {"UK", N_("United Kingdom") }, {"US", N_("United States of America") }, {"UY", N_("Uruguay") }, {"UZ", N_("Uzbekistan") }, {"VA", N_("Vatican City State") }, {"VC", N_("St. Vincent and the Grenadines") }, {"VE", N_("Venezuela") }, {"VG", N_("British Virgin Islands") }, {"VI", N_("US Virgin Islands") }, {"VN", N_("Vietnam") }, {"VU", N_("Vanuatu") }, {"WF", N_("Wallis and Futuna Islands") }, {"WS", N_("Samoa") }, {"XXX", N_("Adult Entertainment") }, {"YE", N_("Yemen") }, {"YT", N_("Mayotte") }, {"YU", N_("Yugoslavia") }, {"ZA", N_("South Africa") }, {"ZM", N_("Zambia") }, {"ZW", N_("Zimbabwe") }, }; char * country (char *hostname) { char *p; domain_t *dom; if (!hostname || !*hostname || isdigit ((unsigned char) hostname[strlen (hostname) - 1])) return _("Unknown"); if ((p = strrchr (hostname, '.'))) p++; else p = hostname; dom = bsearch (p, domain, sizeof (domain) / sizeof (domain_t), sizeof (domain_t), country_compare); if (!dom) return _("Unknown"); return _(dom->country); } void country_search (char *pattern, void *ud, void (*print)(void *, char *, ...)) { const domain_t *dom; int i; for (i = 0; i < sizeof (domain) / sizeof (domain_t); i++) { dom = &domain[i]; if (match (pattern, dom->country) || match (pattern, _(dom->country))) { print (ud, "%s = %s\n", dom->code, _(dom->country)); } } } /* I think gnome1.0.x isn't necessarily linked against popt, ah well! */ /* !!! For now use this inlined function, or it would break fe-text building */ /* .... will find a better solution later. */ /*#ifndef USE_GNOME*/ /* this is taken from gnome-libs 1.2.4 */ #define POPT_ARGV_ARRAY_GROW_DELTA 5 int my_poptParseArgvString(const char * s, int * argcPtr, char *** argvPtr) { char * buf, * bufStart, * dst; const char * src; char quote = '\0'; int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA; char ** argv = malloc(sizeof(*argv) * argvAlloced); const char ** argv2; int argc = 0; int i, buflen; buflen = strlen(s) + 1; /* bufStart = buf = alloca(buflen);*/ bufStart = buf = malloc (buflen); memset(buf, '\0', buflen); src = s; argv[argc] = buf; while (*src) { if (quote == *src) { quote = '\0'; } else if (quote) { if (*src == '\\') { src++; if (!*src) { free(argv); free(bufStart); return 1; } if (*src != quote) *buf++ = '\\'; } *buf++ = *src; /*} else if (isspace((unsigned char) *src)) {*/ } else if (*src == ' ') { if (*argv[argc]) { buf++, argc++; if (argc == argvAlloced) { argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA; argv = realloc(argv, sizeof(*argv) * argvAlloced); } argv[argc] = buf; } } else switch (*src) { case '"': case '\'': quote = *src; break; case '\\': src++; if (!*src) { free(argv); free(bufStart); return 1; } /* fallthrough */ default: *buf++ = *src; } src++; } if (strlen(argv[argc])) { argc++, buf++; } dst = malloc((argc + 1) * sizeof(*argv) + (buf - bufStart)); argv2 = (void *) dst; dst += (argc + 1) * sizeof(*argv); memcpy((void *)argv2, argv, argc * sizeof(*argv)); argv2[argc] = NULL; memcpy(dst, bufStart, buf - bufStart); for (i = 0; i < argc; i++) { argv2[i] = dst + (argv[i] - bufStart); } free(argv); *argvPtr = (char **)argv2; /* XXX don't change the API */ *argcPtr = argc; free (bufStart); return 0; } int util_exec (const char *cmd) { char **argv; int argc; #ifndef WIN32 int pid; int fd; #endif if (my_poptParseArgvString (cmd, &argc, &argv) != 0) return -1; #ifndef WIN32 pid = fork (); if (pid == -1) return -1; if (pid == 0) { /* Now close all open file descriptors except stdin, stdout and stderr */ for (fd = 3; fd < 1024; fd++) close(fd); execvp (argv[0], argv); _exit (0); } else { free (argv); return pid; } #else spawnvp (_P_DETACH, argv[0], argv); free (argv); return 0; #endif } int util_execv (char * const argv[]) { #ifndef WIN32 int pid, fd; pid = fork (); if (pid == -1) return -1; if (pid == 0) { /* Now close all open file descriptors except stdin, stdout and stderr */ for (fd = 3; fd < 1024; fd++) close(fd); execv (argv[0], argv); _exit (0); } else { return pid; } #else spawnv (_P_DETACH, argv[0], argv); return 0; #endif } unsigned long make_ping_time (void) { #ifndef WIN32 struct timeval timev; gettimeofday (&timev, 0); #else GTimeVal timev; g_get_current_time (&timev); #endif return (timev.tv_sec - 50000) * 1000000 + timev.tv_usec; } /************************************************************************ * This technique was borrowed in part from the source code to * ircd-hybrid-5.3 to implement case-insensitive string matches which * are fully compliant with Section 2.2 of RFC 1459, the copyright * of that code being (C) 1990 Jarkko Oikarinen and under the GPL. * * A special thanks goes to Mr. Okarinen for being the one person who * seems to have ever noticed this section in the original RFC and * written code for it. Shame on all the rest of you (myself included). * * --+ Dagmar d'Surreal */ int rfc_casecmp (const char *s1, const char *s2) { register unsigned char *str1 = (unsigned char *) s1; register unsigned char *str2 = (unsigned char *) s2; register int res; while ((res = rfc_tolower (*str1) - rfc_tolower (*str2)) == 0) { if (*str1 == '\0') return 0; str1++; str2++; } return (res); } int rfc_ncasecmp (char *str1, char *str2, int n) { register unsigned char *s1 = (unsigned char *) str1; register unsigned char *s2 = (unsigned char *) str2; register int res; while ((res = rfc_tolower (*s1) - rfc_tolower (*s2)) == 0) { s1++; s2++; n--; if (n == 0 || (*s1 == '\0' && *s2 == '\0')) return 0; } return (res); } const unsigned char rfc_tolowertab[] = { 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; /*static unsigned char touppertab[] = { 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', 0x5f, '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };*/ /*static int rename_utf8 (char *oldname, char *newname) { int sav, res; char *fso, *fsn; fso = xchat_filename_from_utf8 (oldname, -1, 0, 0, 0); if (!fso) return FALSE; fsn = xchat_filename_from_utf8 (newname, -1, 0, 0, 0); if (!fsn) { g_free (fso); return FALSE; } res = rename (fso, fsn); sav = errno; g_free (fso); g_free (fsn); errno = sav; return res; } static int unlink_utf8 (char *fname) { int res; char *fs; fs = xchat_filename_from_utf8 (fname, -1, 0, 0, 0); if (!fs) return FALSE; res = unlink (fs); g_free (fs); return res; }*/ static gboolean file_exists_utf8 (char *fname) { int res; char *fs; fs = xchat_filename_from_utf8 (fname, -1, 0, 0, 0); if (!fs) return FALSE; res = access (fs, F_OK); g_free (fs); if (res == 0) return TRUE; return FALSE; } static gboolean copy_file (char *dl_src, char *dl_dest, int permissions) /* FS encoding */ { int tmp_src, tmp_dest; gboolean ok = FALSE; char dl_tmp[4096]; int return_tmp, return_tmp2; if ((tmp_src = open (dl_src, O_RDONLY | OFLAGS)) == -1) { fprintf (stderr, "Unable to open() file '%s' (%s) !", dl_src, strerror (errno)); return FALSE; } if ((tmp_dest = open (dl_dest, O_WRONLY | O_CREAT | O_TRUNC | OFLAGS, permissions)) < 0) { close (tmp_src); fprintf (stderr, "Unable to create file '%s' (%s) !", dl_src, strerror (errno)); return FALSE; } for (;;) { return_tmp = read (tmp_src, dl_tmp, sizeof (dl_tmp)); if (!return_tmp) { ok = TRUE; break; } if (return_tmp < 0) { fprintf (stderr, "download_move_to_completed_dir(): " "error reading while moving file to save directory (%s)", strerror (errno)); break; } return_tmp2 = write (tmp_dest, dl_tmp, return_tmp); if (return_tmp2 < 0) { fprintf (stderr, "download_move_to_completed_dir(): " "error writing while moving file to save directory (%s)", strerror (errno)); break; } if (return_tmp < sizeof (dl_tmp)) { ok = TRUE; break; } } close (tmp_dest); close (tmp_src); return ok; } /* Takes care of moving a file from a temporary download location to a completed location. Now in UTF-8. */ void move_file_utf8 (char *src_dir, char *dst_dir, char *fname, int dccpermissions) { char src[4096]; char dst[4096]; int res, i; char *src_fs; /* FileSystem encoding */ char *dst_fs; /* if dcc_dir and dcc_completed_dir are the same then we are done */ if (0 == strcmp (src_dir, dst_dir) || 0 == dst_dir[0]) return; /* Already in "completed dir" */ snprintf (src, sizeof (src), "%s/%s", src_dir, fname); snprintf (dst, sizeof (dst), "%s/%s", dst_dir, fname); /* already exists in completed dir? Append a number */ if (file_exists_utf8 (dst)) { for (i = 0; ; i++) { snprintf (dst, sizeof (dst), "%s/%s.%d", dst_dir, fname, i); if (!file_exists_utf8 (dst)) break; } } /* convert UTF-8 to filesystem encoding */ src_fs = xchat_filename_from_utf8 (src, -1, 0, 0, 0); if (!src_fs) return; dst_fs = xchat_filename_from_utf8 (dst, -1, 0, 0, 0); if (!dst_fs) { g_free (src_fs); return; } /* first try a simple rename move */ res = rename (src_fs, dst_fs); if (res == -1 && (errno == EXDEV || errno == EPERM)) { /* link failed because either the two paths aren't on the */ /* same filesystem or the filesystem doesn't support hard */ /* links, so we have to do a copy. */ if (copy_file (src_fs, dst_fs, dccpermissions)) unlink (src_fs); } g_free (dst_fs); g_free (src_fs); } int mkdir_utf8 (char *dir) { int ret; dir = xchat_filename_from_utf8 (dir, -1, 0, 0, 0); if (!dir) return -1; #ifdef WIN32 ret = mkdir (dir); #else ret = mkdir (dir, S_IRUSR | S_IWUSR | S_IXUSR); #endif g_free (dir); return ret; } /* separates a string according to a 'sep' char, then calls the callback function for each token found */ int token_foreach (char *str, char sep, int (*callback) (char *str, void *ud), void *ud) { char t, *start = str; while (1) { if (*str == sep || *str == 0) { t = *str; *str = 0; if (callback (start, ud) < 1) { *str = t; return FALSE; } *str = t; if (*str == 0) break; str++; start = str; } else { /* chars $00-$7f can never be embedded in utf-8 */ str++; } } return TRUE; } /* 31 bit string hash functions */ guint32 str_hash (const char *key) { const char *p = key; guint32 h = *p; if (h) for (p += 1; *p != '\0'; p++) h = (h << 5) - h + *p; return h; } guint32 str_ihash (const unsigned char *key) { const char *p = key; guint32 h = rfc_tolowertab [(guint)*p]; if (h) for (p += 1; *p != '\0'; p++) h = (h << 5) - h + rfc_tolowertab [(guint)*p]; return h; } /* features: 1. "src" must be valid, NULL terminated UTF-8 */ /* 2. "dest" will be left with valid UTF-8 - no partial chars! */ void safe_strcpy (char *dest, const char *src, int bytes_left) { int mbl; while (1) { mbl = g_utf8_skip[*((unsigned char *)src)]; if (bytes_left < (mbl + 1)) /* can't fit with NULL? */ { *dest = 0; break; } if (mbl == 1) /* one byte char */ { *dest = *src; if (*src == 0) break; /* it all fit */ dest++; src++; bytes_left--; } else /* multibyte char */ { memcpy (dest, src, mbl); dest += mbl; src += mbl; bytes_left -= mbl; } } } void canonalize_key (char *key) { char *pos, token; for (pos = key; (token = *pos) != 0; pos++) { if (token != '_' && (token < '0' || token > '9') && (token < 'A' || token > 'Z') && (token < 'a' || token > 'z')) { *pos = '_'; } else { *pos = tolower(token); } } } int portable_mode () { #ifdef WIN32 if ((_access( "portable-mode", 0 )) != -1) { return 1; } else { return 0; } #else return 0; #endif } int hextray_mode () { #ifdef WIN32 if ((_access( "plugins/hextray.dll", 0 )) != -1) { return 1; } else { return 0; } #else return 0; #endif }