1 /*
2  * purple
3  *
4  * Copyright (C) 2002-2003, Herman Bloggs <hermanator12002@yahoo.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
19  *
20  */
21 #include <winsock2.h>
22 #include <ws2tcpip.h>
23 #include <io.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <errno.h>
27 #include <sys/timeb.h>
28 #include <sys/stat.h>
29 #include <time.h>
30 #include <glib.h>
31 #include "config.h"
32 #include "debug.h"
33 #include "libc_internal.h"
34 #include "util.h"
35 #include <glib/gstdio.h>
36 
37 /** This is redefined here because we can't include internal.h */
38 #ifdef ENABLE_NLS
39 #  include <locale.h>
40 #  include <libintl.h>
41 #  define _(String) ((const char *)dgettext(PACKAGE, String))
42 #  ifdef gettext_noop
43 #    define N_(String) gettext_noop (String)
44 #  else
45 #    define N_(String) (String)
46 #  endif
47 #else
48 #  include <locale.h>
49 #  define N_(String) (String)
50 #  ifndef _
51 #    define _(String) ((const char *)String)
52 #  endif
53 #  define ngettext(Singular, Plural, Number) ((Number == 1) ? ((const char *)Singular) : ((const char *)Plural))
54 #  define dngettext(Domain, Singular, Plural, Number) ((Number == 1) ? ((const char *)Singular) : ((const char *)Plural))
55 #endif
56 
57 #ifndef S_ISDIR
58 # define S_ISDIR(m) (((m)&S_IFDIR)==S_IFDIR)
59 #endif
60 
61 static char errbuf[1024];
62 
63 /* helpers */
wpurple_is_socket(int fd)64 static int wpurple_is_socket( int fd ) {
65 	int optval;
66 	int optlen = sizeof(int);
67 
68 	if( (getsockopt(fd, SOL_SOCKET, SO_TYPE, (void*)&optval, &optlen)) == SOCKET_ERROR ) {
69 		int error = WSAGetLastError();
70 		if( error == WSAENOTSOCK )
71 			return FALSE;
72 		else {
73                         purple_debug(PURPLE_DEBUG_WARNING, "wpurple", "wpurple_is_socket: getsockopt returned error: %d\n", error);
74 			return FALSE;
75 		}
76 	}
77 	return TRUE;
78 }
79 
80 /* socket.h */
wpurple_socket(int namespace,int style,int protocol)81 int wpurple_socket (int namespace, int style, int protocol) {
82 	int ret;
83 
84 	ret = socket( namespace, style, protocol );
85 
86 	if( ret == INVALID_SOCKET ) {
87 		errno = WSAGetLastError();
88 		return -1;
89 	}
90 	return ret;
91 }
92 
wpurple_connect(int socket,struct sockaddr * addr,u_long length)93 int wpurple_connect(int socket, struct sockaddr *addr, u_long length) {
94 	int ret;
95 
96 	ret = connect( socket, addr, length );
97 
98 	if( ret == SOCKET_ERROR ) {
99 		errno = WSAGetLastError();
100 		if( errno == WSAEWOULDBLOCK )
101 			errno = WSAEINPROGRESS;
102 		return -1;
103 	}
104 	return 0;
105 }
106 
wpurple_getsockopt(int socket,int level,int optname,void * optval,socklen_t * optlenptr)107 int wpurple_getsockopt(int socket, int level, int optname, void *optval, socklen_t *optlenptr) {
108 	if(getsockopt(socket, level, optname, optval, optlenptr) == SOCKET_ERROR ) {
109 		errno = WSAGetLastError();
110 		return -1;
111 	}
112 	return 0;
113 }
114 
wpurple_setsockopt(int socket,int level,int optname,const void * optval,socklen_t optlen)115 int wpurple_setsockopt(int socket, int level, int optname, const void *optval, socklen_t optlen) {
116 	if(setsockopt(socket, level, optname, optval, optlen) == SOCKET_ERROR ) {
117 		errno = WSAGetLastError();
118 		return -1;
119 	}
120 	return 0;
121 }
122 
wpurple_getsockname(int socket,struct sockaddr * addr,socklen_t * lenptr)123 int wpurple_getsockname(int socket, struct sockaddr *addr, socklen_t *lenptr) {
124         if(getsockname(socket, addr, lenptr) == SOCKET_ERROR) {
125                 errno = WSAGetLastError();
126                 return -1;
127         }
128         return 0;
129 }
130 
wpurple_bind(int socket,struct sockaddr * addr,socklen_t length)131 int wpurple_bind(int socket, struct sockaddr *addr, socklen_t length) {
132         if(bind(socket, addr, length) == SOCKET_ERROR) {
133                 errno = WSAGetLastError();
134                 return -1;
135         }
136         return 0;
137 }
138 
wpurple_listen(int socket,unsigned int n)139 int wpurple_listen(int socket, unsigned int n) {
140         if(listen(socket, n) == SOCKET_ERROR) {
141                 errno = WSAGetLastError();
142                 return -1;
143         }
144         return 0;
145 }
146 
wpurple_sendto(int socket,const void * buf,size_t len,int flags,const struct sockaddr * to,socklen_t tolen)147 int wpurple_sendto(int socket, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) {
148 	int ret;
149 	if ((ret = sendto(socket, buf, len, flags, to, tolen)
150 			) == SOCKET_ERROR) {
151 		errno = WSAGetLastError();
152 		if(errno == WSAEWOULDBLOCK || errno == WSAEINPROGRESS)
153 			errno = EAGAIN;
154 		return -1;
155 	}
156 	return ret;
157 }
158 
159 /* fcntl.h */
160 /* This is not a full implementation of fcntl. Update as needed.. */
wpurple_fcntl(int socket,int command,...)161 int wpurple_fcntl(int socket, int command, ...) {
162 
163 	switch( command ) {
164 	case F_GETFL:
165 		return 0;
166 
167 	case F_SETFL:
168 	{
169 		va_list args;
170 		int val;
171 		int ret=0;
172 
173 		va_start(args, command);
174 		val = va_arg(args, int);
175 		va_end(args);
176 
177 		switch( val ) {
178 		case O_NONBLOCK:
179 		{
180 			u_long imode=1;
181 			ret = ioctlsocket(socket, FIONBIO, &imode);
182 			break;
183 		}
184 		case 0:
185 		{
186 			u_long imode=0;
187 			ret = ioctlsocket(socket, FIONBIO, &imode);
188 			break;
189 		}
190 		default:
191 			errno = EINVAL;
192 			return -1;
193 		}/*end switch*/
194 		if( ret == SOCKET_ERROR ) {
195 			errno = WSAGetLastError();
196 			return -1;
197 		}
198 		return 0;
199 	}
200 	default:
201                 purple_debug(PURPLE_DEBUG_WARNING, "wpurple", "wpurple_fcntl: Unsupported command\n");
202 		return -1;
203 	}/*end switch*/
204 }
205 
206 /* sys/ioctl.h */
wpurple_ioctl(int fd,int command,void * val)207 int wpurple_ioctl(int fd, int command, void* val) {
208 	switch( command ) {
209 	case FIONBIO:
210 	{
211 		if (ioctlsocket(fd, FIONBIO, (unsigned long *)val) == SOCKET_ERROR) {
212 			errno = WSAGetLastError();
213 			return -1;
214 		}
215 		return 0;
216 	}
217 	case SIOCGIFCONF:
218 	{
219 		INTERFACE_INFO InterfaceList[20];
220 		unsigned long nBytesReturned;
221 		if (WSAIoctl(fd, SIO_GET_INTERFACE_LIST,
222 				0, 0, &InterfaceList,
223 				sizeof(InterfaceList), &nBytesReturned,
224 				0, 0) == SOCKET_ERROR) {
225 			errno = WSAGetLastError();
226 			return -1;
227 		} else {
228 			int i;
229 			struct ifconf *ifc = val;
230 			char *tmp = ifc->ifc_buf;
231 			int nNumInterfaces =
232 				nBytesReturned / sizeof(INTERFACE_INFO);
233 			for (i = 0; i < nNumInterfaces; i++) {
234 				INTERFACE_INFO ii = InterfaceList[i];
235 				struct ifreq *ifr = (struct ifreq *) tmp;
236 				struct sockaddr_in *sa = (struct sockaddr_in *) &ifr->ifr_addr;
237 
238 				sa->sin_family = ii.iiAddress.AddressIn.sin_family;
239 				sa->sin_port = ii.iiAddress.AddressIn.sin_port;
240 				sa->sin_addr.s_addr = ii.iiAddress.AddressIn.sin_addr.s_addr;
241 				tmp += sizeof(struct ifreq);
242 
243 				/* Make sure that we can fit in the original buffer */
244 				if (tmp >= (ifc->ifc_buf + ifc->ifc_len + sizeof(struct ifreq))) {
245 					break;
246 				}
247 			}
248 			/* Replace the length with the actually used length */
249 			ifc->ifc_len = ifc->ifc_len - (ifc->ifc_buf - tmp);
250 			return 0;
251 		}
252 	}
253 	default:
254 		errno = EINVAL;
255 		return -1;
256 	}/*end switch*/
257 }
258 
259 /* arpa/inet.h */
wpurple_inet_aton(const char * name,struct in_addr * addr)260 int wpurple_inet_aton(const char *name, struct in_addr *addr) {
261 	if((addr->s_addr = inet_addr(name)) == INADDR_NONE)
262 		return 0;
263 	else
264 		return 1;
265 }
266 
267 /* Thanks to GNU wget for this inet_ntop() implementation */
268 const char *
wpurple_inet_ntop(int af,const void * src,char * dst,socklen_t cnt)269 wpurple_inet_ntop (int af, const void *src, char *dst, socklen_t cnt)
270 {
271   /* struct sockaddr can't accomodate struct sockaddr_in6. */
272   union {
273     struct sockaddr_in6 sin6;
274     struct sockaddr_in sin;
275   } sa;
276   DWORD dstlen = cnt;
277   size_t srcsize;
278 
279   ZeroMemory(&sa, sizeof(sa));
280   switch (af)
281     {
282     case AF_INET:
283       sa.sin.sin_family = AF_INET;
284       sa.sin.sin_addr = *(struct in_addr *) src;
285       srcsize = sizeof (sa.sin);
286       break;
287     case AF_INET6:
288       sa.sin6.sin6_family = AF_INET6;
289       sa.sin6.sin6_addr = *(struct in6_addr *) src;
290       srcsize = sizeof (sa.sin6);
291       break;
292     default:
293       abort ();
294     }
295 
296   if (WSAAddressToString ((struct sockaddr *) &sa, srcsize, NULL, dst, &dstlen) != 0)
297     {
298       errno = WSAGetLastError();
299       return NULL;
300     }
301   return (const char *) dst;
302 }
303 
304 int
wpurple_inet_pton(int af,const char * src,void * dst)305 wpurple_inet_pton(int af, const char *src, void *dst)
306 {
307 	/* struct sockaddr can't accomodate struct sockaddr_in6. */
308 	union {
309 		struct sockaddr_in6 sin6;
310 		struct sockaddr_in sin;
311 	} sa;
312 	size_t srcsize;
313 
314 	switch(af)
315 	{
316 		case AF_INET:
317 			sa.sin.sin_family = AF_INET;
318 			srcsize = sizeof (sa.sin);
319 		break;
320 		case AF_INET6:
321 			sa.sin6.sin6_family = AF_INET6;
322 			srcsize = sizeof (sa.sin6);
323 		break;
324 		default:
325 			errno = WSAEPFNOSUPPORT;
326 			return -1;
327 	}
328 
329 	if (WSAStringToAddress(src, af, NULL, (struct sockaddr *) &sa, &srcsize) != 0)
330 	{
331 		errno = WSAGetLastError();
332 		return -1;
333 	}
334 
335 	switch(af)
336 	{
337 		case AF_INET:
338 			memcpy(dst, &sa.sin.sin_addr, sizeof(sa.sin.sin_addr));
339 		break;
340 		case AF_INET6:
341 			memcpy(dst, &sa.sin6.sin6_addr, sizeof(sa.sin6.sin6_addr));
342 		break;
343 	}
344 
345 	return 1;
346 }
347 
348 
349 /* netdb.h */
wpurple_gethostbyname(const char * name)350 struct hostent* wpurple_gethostbyname(const char *name) {
351 	struct hostent *hp;
352 
353 	if((hp = gethostbyname(name)) == NULL) {
354 		errno = WSAGetLastError();
355 		return NULL;
356 	}
357 	return hp;
358 }
359 
360 /* string.h */
wpurple_strerror(int errornum)361 char* wpurple_strerror(int errornum) {
362 	if (errornum > WSABASEERR) {
363 		switch(errornum) {
364 			case WSAECONNABORTED: /* 10053 */
365 				g_snprintf(errbuf, sizeof(errbuf), "%s", _("Connection interrupted by other software on your computer."));
366 				break;
367 			case WSAECONNRESET: /* 10054 */
368 				g_snprintf(errbuf, sizeof(errbuf), "%s", _("Remote host closed connection."));
369 				break;
370 			case WSAETIMEDOUT: /* 10060 */
371 				g_snprintf(errbuf, sizeof(errbuf), "%s", _("Connection timed out."));
372 				break;
373 			case WSAECONNREFUSED: /* 10061 */
374 				g_snprintf(errbuf, sizeof(errbuf), "%s", _("Connection refused."));
375 				break;
376 			case WSAEADDRINUSE: /* 10048 */
377 				g_snprintf(errbuf, sizeof(errbuf), "%s", _("Address already in use."));
378 				break;
379 			default:
380 				g_snprintf(errbuf, sizeof(errbuf), "Windows socket error #%d", errornum);
381 		}
382 	} else {
383 		const char *tmp = g_strerror(errornum);
384 		g_snprintf(errbuf, sizeof(errbuf), "%s", tmp);
385 	}
386 	return errbuf;
387 }
388 
389 /* unistd.h */
390 
391 /*
392  *  We need to figure out whether fd is a file or socket handle.
393  */
wpurple_read(int fd,void * buf,unsigned int size)394 int wpurple_read(int fd, void *buf, unsigned int size) {
395 	int ret;
396 
397 	if (fd < 0) {
398 		errno = EBADF;
399 		g_return_val_if_reached(-1);
400 	}
401 
402 	if(wpurple_is_socket(fd)) {
403 		if((ret = recv(fd, buf, size, 0)) == SOCKET_ERROR) {
404 			errno = WSAGetLastError();
405 			if(errno == WSAEWOULDBLOCK || errno == WSAEINPROGRESS)
406 				errno = EAGAIN;
407 			return -1;
408 		}
409 #if 0
410 		else if( ret == 0 ) {
411 			/* connection has been gracefully closed */
412 			errno = WSAENOTCONN;
413 			return -1;
414 		}
415 #endif
416 		else {
417 			/* success reading socket */
418 			return ret;
419 		}
420 	} else {
421 		/* fd is not a socket handle.. pass it off to read */
422 		return _read(fd, buf, size);
423 	}
424 }
425 
wpurple_send(int fd,const void * buf,unsigned int size,int flags)426 int wpurple_send(int fd, const void *buf, unsigned int size, int flags) {
427 	int ret;
428 
429 	ret = send(fd, buf, size, flags);
430 
431 	if (ret == SOCKET_ERROR) {
432 		errno = WSAGetLastError();
433 		if(errno == WSAEWOULDBLOCK || errno == WSAEINPROGRESS)
434 			errno = EAGAIN;
435 		return -1;
436 	}
437 	return ret;
438 }
439 
wpurple_write(int fd,const void * buf,unsigned int size)440 int wpurple_write(int fd, const void *buf, unsigned int size) {
441 
442 	if (fd < 0) {
443 		errno = EBADF;
444 		g_return_val_if_reached(-1);
445 	}
446 
447 	if(wpurple_is_socket(fd))
448 		return wpurple_send(fd, buf, size, 0);
449 	else
450 		return _write(fd, buf, size);
451 }
452 
wpurple_recv(int fd,void * buf,size_t len,int flags)453 int wpurple_recv(int fd, void *buf, size_t len, int flags) {
454 	int ret;
455 
456 	if((ret = recv(fd, buf, len, flags)) == SOCKET_ERROR) {
457 			errno = WSAGetLastError();
458 			if(errno == WSAEWOULDBLOCK || errno == WSAEINPROGRESS)
459 				errno = EAGAIN;
460 			return -1;
461 	} else {
462 		return ret;
463 	}
464 }
465 
wpurple_close(int fd)466 int wpurple_close(int fd) {
467 	int ret;
468 
469 	if (fd < 0) {
470 		errno = EBADF;
471 		g_return_val_if_reached(-1);
472 	}
473 
474 	if( wpurple_is_socket(fd) ) {
475 		if( (ret = closesocket(fd)) == SOCKET_ERROR ) {
476 			errno = WSAGetLastError();
477 			return -1;
478 		}
479 		else
480 			return 0;
481 	}
482 	else
483 		return _close(fd);
484 }
485 
wpurple_gethostname(char * name,size_t size)486 int wpurple_gethostname(char *name, size_t size) {
487         if(gethostname(name, size) == SOCKET_ERROR) {
488                 errno = WSAGetLastError();
489 			return -1;
490         }
491         return 0;
492 }
493 
494 /* sys/time.h */
495 
wpurple_gettimeofday(struct timeval * p,struct timezone * z)496 int wpurple_gettimeofday(struct timeval *p, struct timezone *z) {
497 	int res = 0;
498 	struct _timeb timebuffer;
499 
500 	if (z != 0) {
501 		_tzset();
502 		z->tz_minuteswest = _timezone/60;
503 		z->tz_dsttime = _daylight;
504 	}
505 
506 	if (p != 0) {
507 		_ftime(&timebuffer);
508 		p->tv_sec = timebuffer.time;			/* seconds since 1-1-1970 */
509 		p->tv_usec = timebuffer.millitm*1000; 	/* microseconds */
510 	}
511 
512 	return res;
513 }
514 
515 /* stdio.h */
516 
wpurple_rename(const char * oldname,const char * newname)517 int wpurple_rename (const char *oldname, const char *newname) {
518 	return g_rename(oldname, newname);
519 }
520 
521 /* time.h */
522 
wpurple_localtime_r(const time_t * time,struct tm * resultp)523 struct tm * wpurple_localtime_r (const time_t *time, struct tm *resultp) {
524 	struct tm* tmptm;
525 
526 	if(!time)
527 		return NULL;
528 	tmptm = localtime(time);
529 	if(resultp && tmptm)
530 		return memcpy(resultp, tmptm, sizeof(struct tm));
531 	else
532 		return NULL;
533 }
534 
535 /*
536  * Used by purple_utf8_strftime() by way of purple_internal_strftime()
537  * in src/util.c
538  *
539  * Code derived from PostgreSQL src/timezone/pgtz.c:
540  * http://developer.postgresql.org/cvsweb.cgi/pgsql/src/timezone/pgtz.c
541  */
542 
543 /*
544 PostgreSQL Database Management System
545 (formerly known as Postgres, then as Postgres95)
546 
547 Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
548 
549 Portions Copyright (c) 1994, The Regents of the University of California
550 
551 Permission to use, copy, modify, and distribute this software and its
552 documentation for any purpose, without fee, and without a written agreement
553 is hereby granted, provided that the above copyright notice and this
554 paragraph and the following two paragraphs appear in all copies.
555 
556 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
557 DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
558 LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
559 DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
560 POSSIBILITY OF SUCH DAMAGE.
561 
562 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
563 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
564 AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
565 ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
566 PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
567 
568 */
569 static struct
570 {
571 	char *wstd;		/* Windows name of standard timezone */
572 	char *wdst;		/* Windows name of daylight timezone */
573 	char *ustd;		/* Unix name of standard timezone */
574 	char *udst;		/* Unix name of daylight timezone */
575 } win32_tzmap[] =
576 {
577 	{
578 		"", "",
579 		"", "",
580 	},
581 	/*
582 	 * This list was built from the contents of the registry at
583 	 * "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"
584 	 * on Windows XP Professional SP1
585 	 */
586 	{
587 		"Afghanistan Standard Time", "Afghanistan Daylight Time",
588 		"AFT", "AFT"
589 	},
590 	{
591 		"Alaskan Standard Time", "Alaskan Daylight Time",
592 		"AKST", "AKDT"
593 	},
594 	{
595 		"Arab Standard Time", "Arab Daylight Time",
596 		"AST", "AST"
597 	},
598 	{
599 		"Arabian Standard Time", "Arabian Daylight Time",
600 		"GST", "GST"
601 	},
602 	{
603 		"Arabic Standard Time", "Arabic Daylight Time",
604 		"AST", "ADT"
605 	},
606 	{
607 		"Atlantic Standard Time", "Atlantic Daylight Time",
608 		"AST", "ADT"
609 	},
610 	{
611 		"AUS Central Standard Time", "AUS Central Daylight Time",
612 		"CST", "CST"
613 	},
614 	{
615 		"AUS Eastern Standard Time", "AUS Eastern Daylight Time",
616 		"EST", "EST"
617 	},
618 	{
619 		"Azores Standard Time", "Azores Daylight Time",
620 		"AZOT", "AZOST"
621 	},
622 	{
623 		"Canada Central Standard Time", "Canada Central Daylight Time",
624 		"CST", "MDT"
625 	},
626 	{
627 		"Cape Verde Standard Time", "Cape Verde Daylight Time",
628 		"CVT", "CVST"
629 	},
630 	{
631 		"Caucasus Standard Time", "Caucasus Daylight Time",
632 		"AZT", "AZST"
633 	},
634 	{
635 		"Cen. Australia Standard Time", "Cen. Australia Daylight Time",
636 		"CST", "CST"
637 	},
638 	{
639 		"Central America Standard Time", "Central America Daylight Time",
640 		"CST", "CDT"
641 	},
642 	{
643 		"Central Asia Standard Time", "Central Asia Daylight Time",
644 		"BDT", "BDT"
645 	},
646 	{
647 		"Central Europe Standard Time", "Central Europe Daylight Time",
648 		"CET", "CEST"
649 	},
650 	{
651 		"Central European Standard Time", "Central European Daylight Time",
652 		"CET", "CEST"
653 	},
654 	{
655 		"Central Pacific Standard Time", "Central Pacific Daylight Time",
656 		"NCT", "NCST"
657 	},
658 	{
659 		"Central Standard Time", "Central Daylight Time",
660 		"CST", "CDT"
661 	},
662 	{
663 		"China Standard Time", "China Daylight Time",
664 		"HKT", "HKST"
665 	},
666 	{
667 		"Dateline Standard Time", "Dateline Daylight Time",
668 		"GMT+12", "GMT+12"
669 	},
670 	{
671 		"E. Africa Standard Time", "E. Africa Daylight Time",
672 		"EAT", "EAT"
673 	},
674 	{
675 		"E. Australia Standard Time", "E. Australia Daylight Time",
676 		"EST", "EST"
677 	},
678 	{
679 		"E. Europe Standard Time", "E. Europe Daylight Time",
680 		"EET", "EEST"
681 	},
682 	{
683 		"E. South America Standard Time", "E. South America Daylight Time",
684 		"BRT", "BRST"
685 	},
686 	{
687 		"Eastern Standard Time", "Eastern Daylight Time",
688 		"EST", "EDT"
689 	},
690 	{
691 		"Egypt Standard Time", "Egypt Daylight Time",
692 		"EET", "EEST"
693 	},
694 	{
695 		"Ekaterinburg Standard Time", "Ekaterinburg Daylight Time",
696 		"YEKT", "YEKST"
697 	},
698 	{
699 		"Fiji Standard Time", "Fiji Daylight Time",
700 		"FJT", "FJST"
701 	},
702 	{
703 		"FLE Standard Time", "FLE Daylight Time",
704 		"EET", "EEST"
705 	},
706 	{
707 		"GMT Standard Time", "GMT Daylight Time",
708 		"GMT", "IST"
709 	},
710 	{
711 		"Greenland Standard Time", "Greenland Daylight Time",
712 		"WGT", "WGST"
713 	},
714 	{
715 		"Greenwich Standard Time", "Greenwich Daylight Time",
716 		"WET", "WEST"
717 	},
718 	{
719 		"GTB Standard Time", "GTB Daylight Time",
720 		"EET", "EEST"
721 	},
722 	{
723 		"Hawaiian Standard Time", "Hawaiian Daylight Time",
724 		"HST", "HPT"
725 	},
726 	{
727 		"India Standard Time", "India Daylight Time",
728 		"IST", "IST"
729 	},
730 	{
731 		"Iran Standard Time", "Iran Daylight Time",
732 		"IRST", "IRDT"
733 	},
734 	{
735 		"Jerusalem Standard Time", "Jerusalem Daylight Time",
736 		"IST", "IDT"
737 	},
738 	{
739 		"Korea Standard Time", "Korea Daylight Time",
740 		"KST", "KDT"
741 	},
742 	{
743 		"Mexico Standard Time", "Mexico Daylight Time",
744 		"CST", "CDT"
745 	},
746 	{
747 		"Mexico Standard Time", "Mexico Daylight Time",
748 		"BOT", "BOST"
749 	},
750 	{
751 		"Mid-Atlantic Standard Time", "Mid-Atlantic Daylight Time",
752 		"GST", "GST"
753 	},
754 	{
755 		"Mountain Standard Time", "Mountain Daylight Time",
756 		"MST", "MDT"
757 	},
758 	{
759 		"Myanmar Standard Time", "Myanmar Daylight Time",
760 		"MMT", "MMT"
761 	},
762 	{
763 		"N. Central Asia Standard Time", "N. Central Asia Daylight Time",
764 		"ALMT", "ALMST"
765 	},
766 	{
767 		"Nepal Standard Time", "Nepal Daylight Time",
768 		"NPT", "NPT"
769 	},
770 	{
771 		"New Zealand Standard Time", "New Zealand Daylight Time",
772 		"NZST", "NZDT"
773 	},
774 	{
775 		"Newfoundland Standard Time", "Newfoundland Daylight Time",
776 		"NST", "NDT"
777 	},
778 	{
779 		"North Asia East Standard Time", "North Asia East Daylight Time",
780 		"IRKT", "IRKST"
781 	},
782 	{
783 		"North Asia Standard Time", "North Asia Daylight Time",
784 		"KRAT", "KRAST"
785 	},
786 	{
787 		"Pacific SA Standard Time", "Pacific SA Daylight Time",
788 		"CLT", "CLST"
789 	},
790 	{
791 		"Pacific Standard Time", "Pacific Daylight Time",
792 		"PST", "PDT"
793 	},
794 	{
795 		"Romance Standard Time", "Romance Daylight Time",
796 		"CET", "CEST"
797 	},
798 	{
799 		"Russian Standard Time", "Russian Daylight Time",
800 		"MSK", "MSD"
801 	},
802 	{
803 		"SA Eastern Standard Time", "SA Eastern Daylight Time",
804 		"ART", "ARST"
805 	},
806 	{
807 		"SA Pacific Standard Time", "SA Pacific Daylight Time",
808 		"COT", "COST"
809 	},
810 	{
811 		"SA Western Standard Time", "SA Western Daylight Time",
812 		"VET", "VET"
813 	},
814 	{
815 		"Samoa Standard Time", "Samoa Daylight Time",
816 		"SST", "NDT"
817 	},
818 	{
819 		"SE Asia Standard Time", "SE Asia Daylight Time",
820 		"ICT", "ICT"
821 	},
822 	{
823 		"Malay Peninsula Standard Time", "Malay Peninsula Daylight Time",
824 		"MYT", "MALST"
825 	},
826 	{
827 		"South Africa Standard Time", "South Africa Daylight Time",
828 		"CAT", "CAT"
829 	},
830 	{
831 		"Sri Lanka Standard Time", "Sri Lanka Daylight Time",
832 		"LKT", "IST"
833 	},
834 	{
835 		"Taipei Standard Time", "Taipei Daylight Time",
836 		"CST", "CDT"
837 	},
838 	{
839 		"Tasmania Standard Time", "Tasmania Daylight Time",
840 		"EST", "EST"
841 	},
842 	{
843 		"Tokyo Standard Time", "Tokyo Daylight Time",
844 		"JST", "JDT"
845 	},
846 	{
847 		"Tonga Standard Time", "Tonga Daylight Time",
848 		"TOT", "TOST"
849 	},
850 	{
851 		"US Eastern Standard Time", "US Eastern Daylight Time",
852 		"EST", "EDT"
853 	},
854 	{
855 		"US Mountain Standard Time", "US Mountain Daylight Time",
856 		"MST", "MDT"
857 	},
858 	{
859 		"Vladivostok Standard Time", "Vladivostok Daylight Time",
860 		"VLAT", "VLAST"
861 	},
862 	{
863 		"W. Australia Standard Time", "W. Australia Daylight Time",
864 		"WST", "WST"
865 	},
866 
867 	/* Not mapped in PostgreSQL.
868 	 *
869 	 * I mapped this based on the following information... -- rlaager
870 	 * $ cd /usr/share/zoneinfo/Africa
871 	 * $ for i in * ; do echo `TZ=Africa/$i date +"%z %Z"` $i ; done | grep +0100
872 	 * +0100 CET Algiers
873 	 * +0100 WAT Bangui
874 	 * +0100 WAT Brazzaville
875 	 * +0100 CET Ceuta
876 	 * +0100 WAT Douala
877 	 * +0100 WAT Kinshasa
878 	 * +0100 WAT Lagos
879 	 * +0100 WAT Libreville
880 	 * +0100 WAT Luanda
881 	 * +0100 WAT Malabo
882 	 * +0100 WAT Ndjamena
883 	 * +0100 WAT Niamey
884 	 * +0100 WAT Porto-Novo
885 	 * +0100 CET Tunis
886 	 **/
887 	{
888 		"W. Central Africa Standard Time", "W. Central Africa Daylight Time",
889 		"WAT", "WAT"
890 	},
891 
892 	{
893 		"W. Europe Standard Time", "W. Europe Daylight Time",
894 		"CET", "CEST"
895 	},
896 	{
897 		"West Asia Standard Time", "West Asia Daylight Time",
898 		"PKT", "PKST"
899 	},
900 	{
901 		"West Pacific Standard Time", "West Pacific Daylight Time",
902 		"ChST", "ChST"
903 	},
904 	{
905 		"Yakutsk Standard Time", "Yakutsk Daylight Time",
906 		"YAKT", "YAKST"
907 	},
908 	{
909 		NULL, NULL,
910 		NULL, NULL
911 	}
912 };
913 
914 const char *
wpurple_get_timezone_abbreviation(const struct tm * tm)915 wpurple_get_timezone_abbreviation(const struct tm *tm)
916 {
917 	int i;
918 	char tzname[128];
919 	char localtzname[256];
920 	HKEY rootKey;
921 	int idx;
922 
923 	if (!tm)
924 	{
925 		purple_debug_warning("wpurple", "could not determine current date/time: localtime failed\n");
926 		return "";
927 	}
928 
929 	if (strftime(tzname, sizeof(tzname) - 1, "%Z", tm) == 0)
930 	{
931 		purple_debug_error("wpurple", "timezone name is too long for the buffer\n");
932 		return "";
933 	}
934 
935 	for (i = 0; win32_tzmap[i].wstd != NULL; i++)
936 	{
937 		if (purple_strequal(tzname, win32_tzmap[i].wstd))
938 		{
939 #if 0
940 			purple_debug_info("wpurple", "TZ \"%s\" matches Windows timezone \"%s\"\n",
941 			                win32_tzmap[i].ustd, tzname);
942 #endif
943 			/* Cache the Result */
944 			if (i > 0) {
945 				if (win32_tzmap[0].wstd[0] != '\0')
946 					g_free(win32_tzmap[0].wstd);
947 				win32_tzmap[0].wstd = g_strdup(tzname);
948 				win32_tzmap[0].ustd = win32_tzmap[i].ustd;
949 			}
950 
951 			return win32_tzmap[i].ustd;
952 		}
953 		if (purple_strequal(tzname, win32_tzmap[i].wdst))
954 		{
955 #if 0
956 			purple_debug_info("wpurple", "TZ \"%s\" matches Windows timezone \"%s\"\n",
957 			                win32_tzmap[i].udst, tzname);
958 #endif
959 			/* Cache the Result */
960 			if (i > 0) {
961 				if (win32_tzmap[0].wdst[0] != '\0')
962 					g_free(win32_tzmap[0].wdst);
963 				win32_tzmap[0].wdst = g_strdup(tzname);
964 				win32_tzmap[0].udst = win32_tzmap[i].udst;
965 			}
966 
967 			return win32_tzmap[i].udst;
968 		}
969 	}
970 
971 	/*
972 	 * Localized Windows versions return localized names for the timezone.
973 	 * Scan the registry to find the English name, and then try matching
974 	 * against our table again.
975 	 */
976 	memset(localtzname, 0, sizeof(localtzname));
977 	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
978 			   "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
979 					 0,
980 					 KEY_READ,
981 					 &rootKey) != ERROR_SUCCESS)
982 	{
983 		purple_debug_warning("wpurple", "could not open registry key to identify Windows timezone: %i\n", (int) GetLastError());
984 		return "";
985 	}
986 
987 	for (idx = 0;; idx++)
988 	{
989 		char keyname[256];
990 		char zonename[256];
991 		DWORD namesize;
992 		FILETIME lastwrite;
993 		HKEY key;
994 		LONG r;
995 
996 		memset(keyname, 0, sizeof(keyname));
997 		namesize = sizeof(keyname);
998 		if ((r = RegEnumKeyEx(rootKey,
999 							  idx,
1000 							  keyname,
1001 							  &namesize,
1002 							  NULL,
1003 							  NULL,
1004 							  NULL,
1005 							  &lastwrite)) != ERROR_SUCCESS)
1006 		{
1007 			if (r == ERROR_NO_MORE_ITEMS)
1008 				break;
1009 			purple_debug_warning("wpurple", "could not enumerate registry subkeys to identify Windows timezone: %i\n", (int) r);
1010 			break;
1011 		}
1012 
1013 		if ((r = RegOpenKeyEx(rootKey, keyname, 0, KEY_READ, &key)) != ERROR_SUCCESS)
1014 		{
1015 			purple_debug_warning("wpurple", "could not open registry subkey to identify Windows timezone: %i\n", (int) r);
1016 			break;
1017 		}
1018 
1019 		memset(zonename, 0, sizeof(zonename));
1020 		namesize = sizeof(zonename);
1021 		if ((r = RegQueryValueEx(key, "Std", NULL, NULL, (LPBYTE)zonename, &namesize)) != ERROR_SUCCESS)
1022 		{
1023 			purple_debug_warning("wpurple", "could not query value for 'std' to identify Windows timezone: %i\n", (int) r);
1024 			RegCloseKey(key);
1025 			break;
1026 		}
1027 		if (purple_strequal(tzname, zonename))
1028 		{
1029 			/* Matched zone */
1030 			g_strlcpy(localtzname, keyname, sizeof(localtzname));
1031 			RegCloseKey(key);
1032 			break;
1033 		}
1034 		memset(zonename, 0, sizeof(zonename));
1035 		namesize = sizeof(zonename);
1036 		if ((r = RegQueryValueEx(key, "Dlt", NULL, NULL, (LPBYTE)zonename, &namesize)) != ERROR_SUCCESS)
1037 		{
1038 			purple_debug_warning("wpurple", "could not query value for 'dlt' to identify Windows timezone: %i\n", (int) r);
1039 			RegCloseKey(key);
1040 			break;
1041 		}
1042 		if (purple_strequal(tzname, zonename))
1043 		{
1044 			/* Matched DST zone */
1045 			g_strlcpy(localtzname, keyname, sizeof(localtzname));
1046 			RegCloseKey(key);
1047 			break;
1048 		}
1049 
1050 		RegCloseKey(key);
1051 	}
1052 
1053 	RegCloseKey(rootKey);
1054 
1055 	if (localtzname[0])
1056 	{
1057 		/* Found a localized name, so scan for that one too */
1058 		for (i = 0; win32_tzmap[i].wstd != NULL; i++)
1059 		{
1060 			if (purple_strequal(localtzname, win32_tzmap[i].wstd))
1061 			{
1062 #if 0
1063 				purple_debug_info("wpurple", "TZ \"%s\" matches localized Windows timezone \"%s\" (\"%s\")\n",
1064 				                win32_tzmap[i].ustd, tzname, localtzname);
1065 #endif
1066 				/* Cache the Result */
1067 				if (win32_tzmap[0].wstd[0] != '\0')
1068 					g_free(win32_tzmap[0].wstd);
1069 				win32_tzmap[0].wstd = g_strdup(tzname);
1070 				win32_tzmap[0].ustd = win32_tzmap[i].ustd;
1071 
1072 				return win32_tzmap[i].ustd;
1073 			}
1074 			if (purple_strequal(localtzname, win32_tzmap[i].wdst))
1075 			{
1076 #if 0
1077 				purple_debug_info("wpurple", "TZ \"%s\" matches localized Windows timezone \"%s\" (\"%s\")\n",
1078 				                win32_tzmap[i].udst, tzname, localtzname);
1079 #endif
1080 				/* Cache the Result */
1081 				if (win32_tzmap[0].wdst[0] != '\0')
1082 					g_free(win32_tzmap[0].wdst);
1083 
1084 				win32_tzmap[0].wdst = g_strdup(tzname);
1085 				win32_tzmap[0].udst = win32_tzmap[i].udst;
1086 
1087 				return win32_tzmap[i].udst;
1088 			}
1089 		}
1090 	}
1091 
1092 	purple_debug_warning("wpurple", "could not find a match for Windows timezone \"%s\"\n", tzname);
1093 	return "";
1094 }
1095 
1096 int wpurple_g_access (const gchar *filename, int mode);
1097 /**
1098  * @deprecated - remove for 3.0.0
1099  */
1100 int
wpurple_g_access(const gchar * filename,int mode)1101 wpurple_g_access (const gchar *filename, int mode)
1102 {
1103 	return g_access(filename, mode);
1104 }
1105 
1106 
1107