Mercurial > pidgin
diff libpurple/win32/libc_interface.c @ 15373:5fe8042783c1
Rename gtk/ and libgaim/ to pidgin/ and libpurple/
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Sat, 20 Jan 2007 02:32:10 +0000 |
parents | |
children | 32c366eeeb99 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/win32/libc_interface.c Sat Jan 20 02:32:10 2007 +0000 @@ -0,0 +1,1097 @@ +/* + * gaim + * + * Copyright (C) 2002-2003, Herman Bloggs <hermanator12002@yahoo.com> + * + * 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 + * + */ +#include <winsock2.h> +#include <ws2tcpip.h> +#include <io.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <sys/timeb.h> +#include <sys/stat.h> +#include <time.h> +#include <glib.h> +#include "debug.h" +#include "libc_internal.h" +#if GLIB_CHECK_VERSION(2,6,0) +# include <glib/gstdio.h> +#else +#define g_remove remove +#define g_rename rename +#define g_stat stat +#endif + +static char errbuf[1024]; + +/* helpers */ +static int wgaim_is_socket( int fd ) { + int optval; + unsigned int optlen = sizeof(int); + + if( (getsockopt(fd, SOL_SOCKET, SO_TYPE, (void*)&optval, &optlen)) == SOCKET_ERROR ) { + int error = WSAGetLastError(); + if( error == WSAENOTSOCK ) + return FALSE; + else { + gaim_debug(GAIM_DEBUG_WARNING, "wgaim", "wgaim_is_socket: getsockopt returned error: %d\n", error); + return FALSE; + } + } + return TRUE; +} + +/* socket.h */ +int wgaim_socket (int namespace, int style, int protocol) { + int ret; + + ret = socket( namespace, style, protocol ); + + if( ret == INVALID_SOCKET ) { + errno = WSAGetLastError(); + return -1; + } + return ret; +} + +int wgaim_connect(int socket, struct sockaddr *addr, u_long length) { + int ret; + + ret = connect( socket, addr, length ); + + if( ret == SOCKET_ERROR ) { + errno = WSAGetLastError(); + if( errno == WSAEWOULDBLOCK ) + errno = WSAEINPROGRESS; + return -1; + } + return 0; +} + +int wgaim_getsockopt(int socket, int level, int optname, void *optval, socklen_t *optlenptr) { + if(getsockopt(socket, level, optname, optval, optlenptr) == SOCKET_ERROR ) { + errno = WSAGetLastError(); + return -1; + } + return 0; +} + +int wgaim_setsockopt(int socket, int level, int optname, const void *optval, socklen_t optlen) { + if(setsockopt(socket, level, optname, optval, optlen) == SOCKET_ERROR ) { + errno = WSAGetLastError(); + return -1; + } + return 0; +} + +int wgaim_getsockname(int socket, struct sockaddr *addr, socklen_t *lenptr) { + if(getsockname(socket, addr, lenptr) == SOCKET_ERROR) { + errno = WSAGetLastError(); + return -1; + } + return 0; +} + +int wgaim_bind(int socket, struct sockaddr *addr, socklen_t length) { + if(bind(socket, addr, length) == SOCKET_ERROR) { + errno = WSAGetLastError(); + return -1; + } + return 0; +} + +int wgaim_listen(int socket, unsigned int n) { + if(listen(socket, n) == SOCKET_ERROR) { + errno = WSAGetLastError(); + return -1; + } + return 0; +} + +int wgaim_sendto(int socket, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) { + int ret; + if ((ret = sendto(socket, buf, len, flags, to, tolen) + ) == SOCKET_ERROR) { + errno = WSAGetLastError(); + return -1; + } + return ret; +} + +/* fcntl.h */ +/* This is not a full implementation of fcntl. Update as needed.. */ +int wgaim_fcntl(int socket, int command, int val) { + switch( command ) { + case F_SETFL: + { + int ret=0; + + switch( val ) { + case O_NONBLOCK: + { + u_long imode=1; + ret = ioctlsocket(socket, FIONBIO, &imode); + break; + } + case 0: + { + u_long imode=0; + ret = ioctlsocket(socket, FIONBIO, &imode); + break; + } + default: + errno = EINVAL; + return -1; + }/*end switch*/ + if( ret == SOCKET_ERROR ) { + errno = WSAGetLastError(); + return -1; + } + return 0; + } + default: + gaim_debug(GAIM_DEBUG_WARNING, "wgaim", "wgaim_fcntl: Unsupported command\n"); + return -1; + }/*end switch*/ +} + +/* sys/ioctl.h */ +int wgaim_ioctl(int fd, int command, void* val) { + switch( command ) { + case FIONBIO: + { + if (ioctlsocket(fd, FIONBIO, (unsigned long *)val) == SOCKET_ERROR) { + errno = WSAGetLastError(); + return -1; + } + return 0; + } + case SIOCGIFCONF: + { + INTERFACE_INFO InterfaceList[20]; + unsigned long nBytesReturned; + if (WSAIoctl(fd, SIO_GET_INTERFACE_LIST, + 0, 0, &InterfaceList, + sizeof(InterfaceList), &nBytesReturned, + 0, 0) == SOCKET_ERROR) { + errno = WSAGetLastError(); + return -1; + } else { + int i; + struct ifconf *ifc = val; + char *tmp = ifc->ifc_buf; + int nNumInterfaces = + nBytesReturned / sizeof(INTERFACE_INFO); + for (i = 0; i < nNumInterfaces; i++) { + INTERFACE_INFO ii = InterfaceList[i]; + struct ifreq *ifr = (struct ifreq *) tmp; + struct sockaddr_in *sa = (struct sockaddr_in *) &ifr->ifr_addr; + + sa->sin_family = ii.iiAddress.AddressIn.sin_family; + sa->sin_port = ii.iiAddress.AddressIn.sin_port; + sa->sin_addr.s_addr = ii.iiAddress.AddressIn.sin_addr.s_addr; + tmp += sizeof(struct ifreq); + + /* Make sure that we can fit in the original buffer */ + if (tmp >= (ifc->ifc_buf + ifc->ifc_len + sizeof(struct ifreq))) { + break; + } + } + /* Replace the length with the actually used length */ + ifc->ifc_len = ifc->ifc_len - (ifc->ifc_buf - tmp); + return 0; + } + } + default: + errno = EINVAL; + return -1; + }/*end switch*/ +} + +/* arpa/inet.h */ +int wgaim_inet_aton(const char *name, struct in_addr *addr) { + if((addr->s_addr = inet_addr(name)) == INADDR_NONE) + return 0; + else + return 1; +} + +/* Thanks to GNU wget for this inet_ntop() implementation */ +const char * +wgaim_inet_ntop (int af, const void *src, char *dst, socklen_t cnt) +{ + /* struct sockaddr can't accomodate struct sockaddr_in6. */ + union { + struct sockaddr_in6 sin6; + struct sockaddr_in sin; + } sa; + DWORD dstlen = cnt; + size_t srcsize; + + ZeroMemory(&sa, sizeof(sa)); + switch (af) + { + case AF_INET: + sa.sin.sin_family = AF_INET; + sa.sin.sin_addr = *(struct in_addr *) src; + srcsize = sizeof (sa.sin); + break; + case AF_INET6: + sa.sin6.sin6_family = AF_INET6; + sa.sin6.sin6_addr = *(struct in6_addr *) src; + srcsize = sizeof (sa.sin6); + break; + default: + abort (); + } + + if (WSAAddressToString ((struct sockaddr *) &sa, srcsize, NULL, dst, &dstlen) != 0) + { + errno = WSAGetLastError(); + return NULL; + } + return (const char *) dst; +} + + +/* netdb.h */ +struct hostent* wgaim_gethostbyname(const char *name) { + struct hostent *hp; + + if((hp = gethostbyname(name)) == NULL) { + errno = WSAGetLastError(); + return NULL; + } + return hp; +} + +/* string.h */ +char* wgaim_strerror( int errornum ) { + if( errornum > WSABASEERR ) { + sprintf( errbuf, "Windows socket error #%d", errornum ); + return errbuf; + } + else + return strerror( errornum ); +} + +/* unistd.h */ + +/* + * We need to figure out whether fd is a file or socket handle. + */ +int wgaim_read(int fd, void *buf, unsigned int size) { + int ret; + + if(wgaim_is_socket(fd)) { + if((ret = recv(fd, buf, size, 0)) == SOCKET_ERROR) { + errno = WSAGetLastError(); + if(errno == WSAEWOULDBLOCK) + errno = EAGAIN; + return -1; + } +#if 0 + else if( ret == 0 ) { + /* connection has been gracefully closed */ + errno = WSAENOTCONN; + return -1; + } +#endif + else { + /* success reading socket */ + return ret; + } + } else { + /* fd is not a socket handle.. pass it off to read */ + return read(fd, buf, size); + } +} + +int wgaim_send(int fd, const void *buf, unsigned int size, int flags) { + int ret; + + ret = send(fd, buf, size, flags); + + if (ret == SOCKET_ERROR) { + errno = WSAGetLastError(); + if(errno == WSAEWOULDBLOCK) + errno = EAGAIN; + return -1; + } + return ret; +} + +int wgaim_write(int fd, const void *buf, unsigned int size) { + + if(wgaim_is_socket(fd)) + return wgaim_send(fd, buf, size, 0); + else + return write(fd, buf, size); +} + +int wgaim_recv(int fd, void *buf, size_t len, int flags) { + int ret; + + if((ret = recv(fd, buf, len, flags)) == SOCKET_ERROR) { + errno = WSAGetLastError(); + if(errno == WSAEWOULDBLOCK) + errno = EAGAIN; + return -1; + } else { + return ret; + } +} + +int wgaim_close(int fd) { + int ret; + + if( wgaim_is_socket(fd) ) { + if( (ret = closesocket(fd)) == SOCKET_ERROR ) { + errno = WSAGetLastError(); + return -1; + } + else + return 0; + } + else + return close(fd); +} + +int wgaim_gethostname(char *name, size_t size) { + if(gethostname(name, size) == SOCKET_ERROR) { + errno = WSAGetLastError(); + return -1; + } + return 0; +} + +/* sys/time.h */ + +int wgaim_gettimeofday(struct timeval *p, struct timezone *z) { + int res = 0; + struct _timeb timebuffer; + + if (z != 0) { + _tzset(); + z->tz_minuteswest = _timezone/60; + z->tz_dsttime = _daylight; + } + + if (p != 0) { + _ftime(&timebuffer); + p->tv_sec = timebuffer.time; /* seconds since 1-1-1970 */ + p->tv_usec = timebuffer.millitm*1000; /* microseconds */ + } + + return res; +} + +/* stdio.h */ + +int wgaim_rename (const char *oldname, const char *newname) { + struct stat oldstat, newstat; + + if(g_stat(oldname, &oldstat) == 0) { + /* newname exists */ + if(g_stat(newname, &newstat) == 0) { + /* oldname is a dir */ + if(_S_ISDIR(oldstat.st_mode)) { + if(!_S_ISDIR(newstat.st_mode)) { + return g_rename(oldname, newname); + } + /* newname is a dir */ + else { + /* This is not quite right.. If newname is empty and + is not a sub dir of oldname, newname should be + deleted and oldname should be renamed. + */ + gaim_debug(GAIM_DEBUG_WARNING, "wgaim", "wgaim_rename does not behave here as it should\n"); + return g_rename(oldname, newname); + } + } + /* oldname is not a dir */ + else { + /* newname is a dir */ + if(_S_ISDIR(newstat.st_mode)) { + errno = EISDIR; + return -1; + } + /* newname is not a dir */ + else { + g_remove(newname); + return g_rename(oldname, newname); + } + } + } + /* newname doesn't exist */ + else + return g_rename(oldname, newname); + } + else { + /* oldname doesn't exist */ + errno = ENOENT; + return -1; + } + +} + +/* time.h */ + +struct tm * wgaim_localtime_r (const time_t *time, struct tm *resultp) { + struct tm* tmptm; + + if(!time) + return NULL; + tmptm = localtime(time); + if(resultp && tmptm) + return memcpy(resultp, tmptm, sizeof(struct tm)); + else + return NULL; +} + +/* + * Used by gaim_utf8_strftime() by way of gaim_internal_strftime() + * in src/util.c + * + * Code derived from PostgreSQL src/timezone/pgtz.c: + * http://developer.postgresql.org/cvsweb.cgi/pgsql/src/timezone/pgtz.c + */ + +/* +PostgreSQL Database Management System +(formerly known as Postgres, then as Postgres95) + +Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group + +Portions Copyright (c) 1994, The Regents of the University of California + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose, without fee, and without a written agreement +is hereby granted, provided that the above copyright notice and this +paragraph and the following two paragraphs appear in all copies. + +IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR +DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING +LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS +DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS +ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO +PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +*/ +static struct +{ + char *wstd; /* Windows name of standard timezone */ + char *wdst; /* Windows name of daylight timezone */ + char *ustd; /* Unix name of standard timezone */ + char *udst; /* Unix name of daylight timezone */ +} win32_tzmap[] = +{ + { + "", "", + "", "", + }, + /* + * This list was built from the contents of the registry at + * "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones" + * on Windows XP Professional SP1 + */ + { + "Afghanistan Standard Time", "Afghanistan Daylight Time", + "AFT", "AFT" + }, + { + "Alaskan Standard Time", "Alaskan Daylight Time", + "AKST", "AKDT" + }, + { + "Arab Standard Time", "Arab Daylight Time", + "AST", "AST" + }, + { + "Arabian Standard Time", "Arabian Daylight Time", + "GST", "GST" + }, + { + "Arabic Standard Time", "Arabic Daylight Time", + "AST", "ADT" + }, + { + "Atlantic Standard Time", "Atlantic Daylight Time", + "AST", "ADT" + }, + { + "AUS Central Standard Time", "AUS Central Daylight Time", + "CST", "CST" + }, + { + "AUS Eastern Standard Time", "AUS Eastern Daylight Time", + "EST", "EST" + }, + { + "Azores Standard Time", "Azores Daylight Time", + "AZOT", "AZOST" + }, + { + "Canada Central Standard Time", "Canada Central Daylight Time", + "CST", "MDT" + }, + { + "Cape Verde Standard Time", "Cape Verde Daylight Time", + "CVT", "CVST" + }, + { + "Caucasus Standard Time", "Caucasus Daylight Time", + "AZT", "AZST" + }, + { + "Cen. Australia Standard Time", "Cen. Australia Daylight Time", + "CST", "CST" + }, + { + "Central America Standard Time", "Central America Daylight Time", + "CST", "CDT" + }, + { + "Central Asia Standard Time", "Central Asia Daylight Time", + "BDT", "BDT" + }, + { + "Central Europe Standard Time", "Central Europe Daylight Time", + "CET", "CEST" + }, + { + "Central European Standard Time", "Central European Daylight Time", + "CET", "CEST" + }, + { + "Central Pacific Standard Time", "Central Pacific Daylight Time", + "NCT", "NCST" + }, + { + "Central Standard Time", "Central Daylight Time", + "CST", "CDT" + }, + { + "China Standard Time", "China Daylight Time", + "HKT", "HKST" + }, + { + "Dateline Standard Time", "Dateline Daylight Time", + "GMT+12", "GMT+12" + }, + { + "E. Africa Standard Time", "E. Africa Daylight Time", + "EAT", "EAT" + }, + { + "E. Australia Standard Time", "E. Australia Daylight Time", + "EST", "EST" + }, + { + "E. Europe Standard Time", "E. Europe Daylight Time", + "EET", "EEST" + }, + { + "E. South America Standard Time", "E. South America Daylight Time", + "BRT", "BRST" + }, + { + "Eastern Standard Time", "Eastern Daylight Time", + "EST", "EDT" + }, + { + "Egypt Standard Time", "Egypt Daylight Time", + "EET", "EEST" + }, + { + "Ekaterinburg Standard Time", "Ekaterinburg Daylight Time", + "YEKT", "YEKST" + }, + { + "Fiji Standard Time", "Fiji Daylight Time", + "FJT", "FJST" + }, + { + "FLE Standard Time", "FLE Daylight Time", + "EET", "EEST" + }, + { + "GMT Standard Time", "GMT Daylight Time", + "GMT", "IST" + }, + { + "Greenland Standard Time", "Greenland Daylight Time", + "WGT", "WGST" + }, + { + "Greenwich Standard Time", "Greenwich Daylight Time", + "WET", "WEST" + }, + { + "GTB Standard Time", "GTB Daylight Time", + "EET", "EEST" + }, + { + "Hawaiian Standard Time", "Hawaiian Daylight Time", + "HST", "HPT" + }, + { + "India Standard Time", "India Daylight Time", + "IST", "IST" + }, + { + "Iran Standard Time", "Iran Daylight Time", + "IRST", "IRDT" + }, + { + "Jerusalem Standard Time", "Jerusalem Daylight Time", + "IST", "IDT" + }, + { + "Korea Standard Time", "Korea Daylight Time", + "KST", "KDT" + }, + { + "Mexico Standard Time", "Mexico Daylight Time", + "CST", "CDT" + }, + { + "Mexico Standard Time", "Mexico Daylight Time", + "BOT", "BOST" + }, + { + "Mid-Atlantic Standard Time", "Mid-Atlantic Daylight Time", + "GST", "GST" + }, + { + "Mountain Standard Time", "Mountain Daylight Time", + "MST", "MDT" + }, + { + "Myanmar Standard Time", "Myanmar Daylight Time", + "MMT", "MMT" + }, + { + "N. Central Asia Standard Time", "N. Central Asia Daylight Time", + "ALMT", "ALMST" + }, + { + "Nepal Standard Time", "Nepal Daylight Time", + "NPT", "NPT" + }, + { + "New Zealand Standard Time", "New Zealand Daylight Time", + "NZST", "NZDT" + }, + { + "Newfoundland Standard Time", "Newfoundland Daylight Time", + "NST", "NDT" + }, + { + "North Asia East Standard Time", "North Asia East Daylight Time", + "IRKT", "IRKST" + }, + { + "North Asia Standard Time", "North Asia Daylight Time", + "KRAT", "KRAST" + }, + { + "Pacific SA Standard Time", "Pacific SA Daylight Time", + "CLT", "CLST" + }, + { + "Pacific Standard Time", "Pacific Daylight Time", + "PST", "PDT" + }, + { + "Romance Standard Time", "Romance Daylight Time", + "CET", "CEST" + }, + { + "Russian Standard Time", "Russian Daylight Time", + "MSK", "MSD" + }, + { + "SA Eastern Standard Time", "SA Eastern Daylight Time", + "ART", "ARST" + }, + { + "SA Pacific Standard Time", "SA Pacific Daylight Time", + "COT", "COST" + }, + { + "SA Western Standard Time", "SA Western Daylight Time", + "VET", "VET" + }, + { + "Samoa Standard Time", "Samoa Daylight Time", + "SST", "NDT" + }, + { + "SE Asia Standard Time", "SE Asia Daylight Time", + "ICT", "ICT" + }, + { + "Malay Peninsula Standard Time", "Malay Peninsula Daylight Time", + "MYT", "MALST" + }, + { + "South Africa Standard Time", "South Africa Daylight Time", + "CAT", "CAT" + }, + { + "Sri Lanka Standard Time", "Sri Lanka Daylight Time", + "LKT", "IST" + }, + { + "Taipei Standard Time", "Taipei Daylight Time", + "CST", "CDT" + }, + { + "Tasmania Standard Time", "Tasmania Daylight Time", + "EST", "EST" + }, + { + "Tokyo Standard Time", "Tokyo Daylight Time", + "JST", "JDT" + }, + { + "Tonga Standard Time", "Tonga Daylight Time", + "TOT", "TOST" + }, + { + "US Eastern Standard Time", "US Eastern Daylight Time", + "EST", "EDT" + }, + { + "US Mountain Standard Time", "US Mountain Daylight Time", + "MST", "MDT" + }, + { + "Vladivostok Standard Time", "Vladivostok Daylight Time", + "VLAT", "VLAST" + }, + { + "W. Australia Standard Time", "W. Australia Daylight Time", + "WST", "WST" + }, + + /* Not mapped in PostgreSQL. + * + * I mapped this based on the following information... -- rlaager + * $ cd /usr/share/zoneinfo/Africa + * $ for i in * ; do echo `TZ=Africa/$i date +"%z %Z"` $i ; done | grep +0100 + * +0100 CET Algiers + * +0100 WAT Bangui + * +0100 WAT Brazzaville + * +0100 CET Ceuta + * +0100 WAT Douala + * +0100 WAT Kinshasa + * +0100 WAT Lagos + * +0100 WAT Libreville + * +0100 WAT Luanda + * +0100 WAT Malabo + * +0100 WAT Ndjamena + * +0100 WAT Niamey + * +0100 WAT Porto-Novo + * +0100 CET Tunis + **/ + { + "W. Central Africa Standard Time", "W. Central Africa Daylight Time", + "WAT", "WAT" + }, + + { + "W. Europe Standard Time", "W. Europe Daylight Time", + "CET", "CEST" + }, + { + "West Asia Standard Time", "West Asia Daylight Time", + "PKT", "PKST" + }, + { + "West Pacific Standard Time", "West Pacific Daylight Time", + "ChST", "ChST" + }, + { + "Yakutsk Standard Time", "Yakutsk Daylight Time", + "YAKT", "YAKST" + }, + { + NULL, NULL, + NULL, NULL + } +}; + +const char * +wgaim_get_timezone_abbreviation(const struct tm *tm) +{ + int i; + char tzname[128]; + char localtzname[256]; + HKEY rootKey; + int idx; + + if (!tm) + { + gaim_debug_warning("wgaim", "could not determine current date/time: localtime failed\n"); + return ""; + } + + if (strftime(tzname, sizeof(tzname) - 1, "%Z", tm) == 0) + { + gaim_debug_error("wgaim", "timezone name is too long for the buffer\n"); + return ""; + } + + for (i = 0; win32_tzmap[i].wstd != NULL; i++) + { + if (strcmp(tzname, win32_tzmap[i].wstd) == 0) + { +#if 0 + gaim_debug_info("wgaim", "TZ \"%s\" matches Windows timezone \"%s\"\n", + win32_tzmap[i].ustd, tzname); +#endif + /* Cache the Result */ + if (i > 0) { + if (win32_tzmap[0].wstd[0] != '\0') + g_free(win32_tzmap[0].wstd); + win32_tzmap[0].wstd = g_strdup(tzname); + win32_tzmap[0].ustd = win32_tzmap[i].ustd; + } + + return win32_tzmap[i].ustd; + } + if (strcmp(tzname, win32_tzmap[i].wdst) == 0) + { +#if 0 + gaim_debug_info("wgaim", "TZ \"%s\" matches Windows timezone \"%s\"\n", + win32_tzmap[i].udst, tzname); +#endif + /* Cache the Result */ + if (i > 0) { + if (win32_tzmap[0].wdst[0] != '\0') + g_free(win32_tzmap[0].wdst); + win32_tzmap[0].wdst = g_strdup(tzname); + win32_tzmap[0].udst = win32_tzmap[i].udst; + } + + return win32_tzmap[i].udst; + } + } + + /* + * Localized Windows versions return localized names for the timezone. + * Scan the registry to find the English name, and then try matching + * against our table again. + */ + memset(localtzname, 0, sizeof(localtzname)); + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, + "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", + 0, + KEY_READ, + &rootKey) != ERROR_SUCCESS) + { + gaim_debug_warning("wgaim", "could not open registry key to identify Windows timezone: %i\n", (int) GetLastError()); + return ""; + } + + for (idx = 0;; idx++) + { + char keyname[256]; + char zonename[256]; + DWORD namesize; + FILETIME lastwrite; + HKEY key; + LONG r; + + memset(keyname, 0, sizeof(keyname)); + namesize = sizeof(keyname); + if ((r = RegEnumKeyEx(rootKey, + idx, + keyname, + &namesize, + NULL, + NULL, + NULL, + &lastwrite)) != ERROR_SUCCESS) + { + if (r == ERROR_NO_MORE_ITEMS) + break; + gaim_debug_warning("wgaim", "could not enumerate registry subkeys to identify Windows timezone: %i\n", (int) r); + break; + } + + if ((r = RegOpenKeyEx(rootKey, keyname, 0, KEY_READ, &key)) != ERROR_SUCCESS) + { + gaim_debug_warning("wgaim", "could not open registry subkey to identify Windows timezone: %i\n", (int) r); + break; + } + + memset(zonename, 0, sizeof(zonename)); + namesize = sizeof(zonename); + if ((r = RegQueryValueEx(key, "Std", NULL, NULL, zonename, &namesize)) != ERROR_SUCCESS) + { + gaim_debug_warning("wgaim", "could not query value for 'std' to identify Windows timezone: %i\n", (int) r); + RegCloseKey(key); + break; + } + if (strcmp(tzname, zonename) == 0) + { + /* Matched zone */ + strcpy(localtzname, keyname); + RegCloseKey(key); + break; + } + memset(zonename, 0, sizeof(zonename)); + namesize = sizeof(zonename); + if ((r = RegQueryValueEx(key, "Dlt", NULL, NULL, zonename, &namesize)) != ERROR_SUCCESS) + { + gaim_debug_warning("wgaim", "could not query value for 'dlt' to identify Windows timezone: %i\n", (int) r); + RegCloseKey(key); + break; + } + if (strcmp(tzname, zonename) == 0) + { + /* Matched DST zone */ + strcpy(localtzname, keyname); + RegCloseKey(key); + break; + } + + RegCloseKey(key); + } + + RegCloseKey(rootKey); + + if (localtzname[0]) + { + /* Found a localized name, so scan for that one too */ + for (i = 0; win32_tzmap[i].wstd != NULL; i++) + { + if (strcmp(localtzname, win32_tzmap[i].wstd) == 0) + { +#if 0 + gaim_debug_info("wgaim", "TZ \"%s\" matches localized Windows timezone \"%s\" (\"%s\")\n", + win32_tzmap[i].ustd, tzname, localtzname); +#endif + /* Cache the Result */ + if (win32_tzmap[0].wstd[0] != '\0') + g_free(win32_tzmap[0].wstd); + win32_tzmap[0].wstd = g_strdup(tzname); + win32_tzmap[0].ustd = win32_tzmap[i].ustd; + + return win32_tzmap[i].ustd; + } + if (strcmp(localtzname, win32_tzmap[i].wdst) == 0) + { +#if 0 + gaim_debug_info("wgaim", "TZ \"%s\" matches localized Windows timezone \"%s\" (\"%s\")\n", + win32_tzmap[i].udst, tzname, localtzname); +#endif + /* Cache the Result */ + if (win32_tzmap[0].wdst[0] != '\0') + g_free(win32_tzmap[0].wdst); + + win32_tzmap[0].wdst = g_strdup(tzname); + win32_tzmap[0].udst = win32_tzmap[i].udst; + + return win32_tzmap[i].udst; + } + } + } + + gaim_debug_warning("wgaim", "could not find a match for Windows timezone \"%s\"\n", tzname); + return ""; +} + +#if !GLIB_CHECK_VERSION(2,8,0) +/** + * g_access: + * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows) + * @mode: as in access() + * + * A wrapper for the POSIX access() function. This function is used to + * test a pathname for one or several of read, write or execute + * permissions, or just existence. On Windows, the underlying access() + * function in the C library only checks the READONLY attribute, and + * does not look at the ACL at all. Software that needs to handle file + * permissions on Windows more exactly should use the Win32 API. + * + * See the C library manual for more details about access(). + * + * Returns: zero if the pathname refers to an existing file system + * object that has all the tested permissions, or -1 otherwise or on + * error. + * + * Since: 2.8 + */ +int +wgaim_g_access (const gchar *filename, + int mode) +{ + if (G_WIN32_HAVE_WIDECHAR_API ()) + { + wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL); + int retval; + int save_errno; + + if (wfilename == NULL) + { + errno = EINVAL; + return -1; + } + + retval = _waccess (wfilename, mode); + save_errno = errno; + + g_free (wfilename); + + errno = save_errno; + return retval; + } + else + { + gchar *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL); + int retval; + int save_errno; + + if (cp_filename == NULL) + { + errno = EINVAL; + return -1; + } + + retval = access (cp_filename, mode); + save_errno = errno; + + g_free (cp_filename); + + errno = save_errno; + return retval; + } +} +#endif + +