imapext-2007

view src/osdep/nt/env_nt.c @ 0:ada5e610ab86

imap-2007e
author yuuji@gentei.org
date Mon, 14 Sep 2009 15:17:45 +0900
parents
children
line source
1 /* ========================================================================
2 * Copyright 1988-2008 University of Washington
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 *
11 * ========================================================================
12 */
14 /*
15 * Program: NT environment routines
16 *
17 * Author: Mark Crispin
18 * UW Technology
19 * University of Washington
20 * Seattle, WA 98195
21 * Internet: MRC@Washington.EDU
22 *
23 * Date: 1 August 1988
24 * Last Edited: 15 February 2008
25 */
27 static char *myUserName = NIL; /* user name */
28 static char *myLocalHost = NIL; /* local host name */
29 static char *myHomeDir = NIL; /* home directory name */
30 static char *myNewsrc = NIL; /* newsrc file name */
31 static char *sysInbox = NIL; /* system inbox name */
32 static long list_max_level = 5; /* maximum level of list recursion */
33 /* block environment init */
34 static short block_env_init = NIL;
35 static short no822tztext = NIL; /* disable RFC [2]822 timezone text */
36 /* home namespace */
37 static NAMESPACE nshome = {"",'\\',NIL,NIL};
38 /* UNIX other user namespace */
39 static NAMESPACE nsother = {"#user.",'\\',NIL,NIL};
40 /* namespace list */
41 static NAMESPACE *nslist[3] = {&nshome,&nsother,NIL};
42 static long alarm_countdown = 0;/* alarm count down */
43 static void (*alarm_rang) (); /* alarm interrupt function */
44 static unsigned int rndm = 0; /* initial `random' number */
45 static int server_nli = 0; /* server and not logged in */
46 static int logtry = 3; /* number of login tries */
47 /* block notification */
48 static blocknotify_t mailblocknotify = mm_blocknotify;
49 /* callback to get username */
50 static userprompt_t mailusername = NIL;
51 static long is_nt = -1; /* T if NT, NIL if not NT, -1 unknown */
52 static HINSTANCE netapi = NIL;
53 typedef NET_API_STATUS (CALLBACK *GETINFO) (LPCWSTR,LPCWSTR,DWORD,LPBYTE *);
54 static GETINFO getinfo = NIL;
56 #include "write.c" /* include safe writing routines */
57 #include "pmatch.c" /* include wildcard pattern matcher */
60 /* Get all authenticators */
62 #include "auths.c"
64 /* Environment manipulate parameters
65 * Accepts: function code
66 * function-dependent value
67 * Returns: function-dependent return value
68 */
70 void *env_parameters (long function,void *value)
71 {
72 void *ret = NIL;
73 switch ((int) function) {
74 case GET_NAMESPACE:
75 ret = (void *) nslist;
76 break;
77 case SET_USERPROMPT :
78 mailusername = (userprompt_t) value;
79 case GET_USERPROMPT :
80 ret = (void *) mailusername;
81 break;
82 case SET_HOMEDIR:
83 if (myHomeDir) fs_give ((void **) &myHomeDir);
84 myHomeDir = cpystr ((char *) value);
85 case GET_HOMEDIR:
86 ret = (void *) myHomeDir;
87 break;
88 case SET_LOCALHOST:
89 myLocalHost = cpystr ((char *) value);
90 case GET_LOCALHOST:
91 if (myLocalHost) fs_give ((void **) &myLocalHost);
92 ret = (void *) myLocalHost;
93 break;
94 case SET_NEWSRC:
95 if (myNewsrc) fs_give ((void **) &myNewsrc);
96 myNewsrc = cpystr ((char *) value);
97 case GET_NEWSRC:
98 if (!myNewsrc) { /* set news file name if not defined */
99 char tmp[MAILTMPLEN];
100 sprintf (tmp,"%s\\NEWSRC",myhomedir ());
101 myNewsrc = cpystr (tmp);
102 }
103 ret = (void *) myNewsrc;
104 break;
105 case SET_SYSINBOX:
106 if (sysInbox) fs_give ((void **) &sysInbox);
107 sysInbox = cpystr ((char *) value);
108 case GET_SYSINBOX:
109 ret = (void *) sysInbox;
110 break;
111 case SET_LISTMAXLEVEL:
112 list_max_level = (long) value;
113 case GET_LISTMAXLEVEL:
114 ret = (void *) list_max_level;
115 break;
116 case SET_DISABLE822TZTEXT:
117 no822tztext = value ? T : NIL;
118 case GET_DISABLE822TZTEXT:
119 ret = (void *) (no822tztext ? VOIDT : NIL);
120 break;
121 case SET_BLOCKENVINIT:
122 block_env_init = value ? T : NIL;
123 case GET_BLOCKENVINIT:
124 ret = (void *) (block_env_init ? VOIDT : NIL);
125 break;
126 case SET_BLOCKNOTIFY:
127 mailblocknotify = (blocknotify_t) value;
128 case GET_BLOCKNOTIFY:
129 ret = (void *) mailblocknotify;
130 break;
131 }
132 return ret;
133 }
135 /* Write current time
136 * Accepts: destination string
137 * optional format of day-of-week prefix
138 * format of date and time
139 * flag whether to append symbolic timezone
140 */
142 static void do_date (char *date,char *prefix,char *fmt,int suffix)
143 {
144 time_t tn = time (0);
145 struct tm *t = gmtime (&tn);
146 int zone = t->tm_hour * 60 + t->tm_min;
147 int julian = t->tm_yday;
148 t = localtime (&tn); /* get local time now */
149 /* minus UTC minutes since midnight */
150 zone = t->tm_hour * 60 + t->tm_min - zone;
151 /* julian can be one of:
152 * 36x local time is December 31, UTC is January 1, offset -24 hours
153 * 1 local time is 1 day ahead of UTC, offset +24 hours
154 * 0 local time is same day as UTC, no offset
155 * -1 local time is 1 day behind UTC, offset -24 hours
156 * -36x local time is January 1, UTC is December 31, offset +24 hours
157 */
158 if (julian = t->tm_yday -julian)
159 zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
160 if (prefix) { /* want day of week? */
161 sprintf (date,prefix,days[t->tm_wday]);
162 date += strlen (date); /* make next sprintf append */
163 }
164 /* output the date */
165 sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
166 t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
167 if (suffix) { /* append timezone suffix if desired */
168 char *tz;
169 tzset (); /* get timezone from TZ environment stuff */
170 tz = tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0];
171 if (tz && tz[0]) {
172 char *s;
173 for (s = tz; *s; s++) if (*s & 0x80) return;
174 sprintf (date + strlen (date)," (%.50s)",tz);
175 }
176 }
177 }
180 /* Write current time in RFC 822 format
181 * Accepts: destination string
182 */
184 void rfc822_date (char *date)
185 {
186 do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
187 no822tztext ? NIL : T);
188 }
191 /* Write current time in fixed-width RFC 822 format
192 * Accepts: destination string
193 */
195 void rfc822_fixed_date (char *date)
196 {
197 do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL);
198 }
201 /* Write current time in internal format
202 * Accepts: destination string
203 */
205 void internal_date (char *date)
206 {
207 do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
208 }
210 /* Return random number
211 */
213 long random (void)
214 {
215 if (!rndm) srand (rndm = (unsigned) time (0L));
216 return (long) rand ();
217 }
220 /* Set alarm timer
221 * Accepts: new value
222 * Returns: old alarm value
223 */
225 long alarm (long seconds)
226 {
227 long ret = alarm_countdown;
228 alarm_countdown = seconds;
229 return ret;
230 }
233 /* The clock ticked
234 */
236 void CALLBACK clock_ticked (UINT IDEvent,UINT uReserved,DWORD dwUser,
237 DWORD dwReserved1,DWORD dwReserved2)
238 {
239 if (alarm_rang && !--alarm_countdown) (*alarm_rang) ();
240 }
242 /* Initialize server
243 * Accepts: server name for syslog or NIL
244 * /etc/services service name or NIL
245 * alternate /etc/services service name or NIL
246 * clock interrupt handler
247 * kiss-of-death interrupt handler
248 * hangup interrupt handler
249 * termination interrupt handler
250 */
252 void server_init (char *server,char *service,char *sslservice,
253 void *clkint,void *kodint,void *hupint,void *trmint,
254 void *staint)
255 {
256 if (!check_nt ()) {
257 if (!auth_md5.server) fatal ("Can't run on Windows without MD5 database");
258 server_nli = T; /* Windows server not logged in */
259 }
260 /* only do this if for init call */
261 if (server && service && sslservice) {
262 long port;
263 struct servent *sv;
264 /* set server name in syslog */
265 openlog (server,LOG_PID,LOG_MAIL);
266 fclose (stderr); /* possibly save a process ID */
267 /* Use SSL if SSL service, or if server starts with "s" and not service */
268 if (((port = tcp_serverport ()) >= 0)) {
269 if ((sv = getservbyname (service,"tcp")) && (port == ntohs (sv->s_port)))
270 syslog (LOG_DEBUG,"%s service init from %s",service,tcp_clientaddr ());
271 else if ((sv = getservbyname (sslservice,"tcp")) &&
272 (port == ntohs (sv->s_port))) {
273 syslog (LOG_DEBUG,"%s SSL service init from %s",sslservice,
274 tcp_clientaddr ());
275 ssl_server_init (server);
276 }
277 else { /* not service or SSL service port */
278 syslog (LOG_DEBUG,"port %ld service init from %s",port,
279 tcp_clientaddr ());
280 if (*server == 's') ssl_server_init (server);
281 }
282 }
283 /* make sure stdout does binary */
284 setmode (fileno (stdin),O_BINARY);
285 setmode (fileno (stdout),O_BINARY);
286 }
287 alarm_rang = clkint; /* note the clock interrupt */
288 timeBeginPeriod (1000); /* set the timer interval */
289 timeSetEvent (1000,1000,clock_ticked,NIL,TIME_PERIODIC);
290 }
293 /* Wait for stdin input
294 * Accepts: timeout in seconds
295 * Returns: T if have input on stdin, else NIL
296 */
298 long server_input_wait (long seconds)
299 {
300 fd_set rfd,efd;
301 struct timeval tmo;
302 FD_ZERO (&rfd);
303 FD_ZERO (&efd);
304 FD_SET (0,&rfd);
305 FD_SET (0,&efd);
306 tmo.tv_sec = seconds; tmo.tv_usec = 0;
307 return select (1,&rfd,0,&efd,&tmo) ? LONGT : NIL;
308 }
310 /* Server log in
311 * Accepts: user name string
312 * password string
313 * authenticating user name string
314 * argument count
315 * argument vector
316 * Returns: T if password validated, NIL otherwise
317 */
319 static int gotprivs = NIL; /* once-only flag to grab privileges */
321 long server_login (char *user,char *pass,char *authuser,int argc,char *argv[])
322 {
323 HANDLE hdl;
324 LUID tcbpriv;
325 TOKEN_PRIVILEGES tkp;
326 char *s;
327 /* need to get privileges? */
328 if (!gotprivs++ && check_nt ()) {
329 /* hack for inetlisn */
330 if (argc >= 2) myClientHost = argv[1];
331 /* get process token and TCB priv value */
332 if (!(OpenProcessToken (GetCurrentProcess (),
333 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&hdl) &&
334 LookupPrivilegeValue ((LPSTR) NIL,SE_TCB_NAME,&tcbpriv)))
335 return NIL;
336 tkp.PrivilegeCount = 1; /* want to enable this privilege */
337 tkp.Privileges[0].Luid = tcbpriv;
338 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
339 /* enable it */
340 AdjustTokenPrivileges (hdl,NIL,&tkp,sizeof (TOKEN_PRIVILEGES),
341 (PTOKEN_PRIVILEGES) NIL,(PDWORD) NIL);
342 /* make sure it won */
343 if (GetLastError() != ERROR_SUCCESS) return NIL;
344 }
346 /* cretins still haven't given up */
347 if ((strlen (user) >= MAILTMPLEN) ||
348 (authuser && (strlen (authuser) >= MAILTMPLEN)))
349 syslog (LOG_ALERT,"SYSTEM BREAK-IN ATTEMPT, host=%.80s",tcp_clienthost ());
350 else if (logtry > 0) { /* still have available logins? */
351 /* authentication user not supported */
352 if (authuser && *authuser && compare_cstring (authuser,user))
353 mm_log ("Authentication id must match authorization id",ERROR);
354 if (check_nt ()) { /* NT: authserver_login() call not supported */
355 if (!pass) mm_log ("Unsupported authentication mechanism",ERROR);
356 else if (( /* try to login and impersonate the guy */
357 #ifdef LOGIN32_LOGON_NETWORK
358 LogonUser (user,".",pass,LOGON32_LOGON_NETWORK,
359 LOGON32_PROVIDER_DEFAULT,&hdl) ||
360 #endif
361 LogonUser (user,".",pass,LOGON32_LOGON_INTERACTIVE,
362 LOGON32_PROVIDER_DEFAULT,&hdl) ||
363 LogonUser (user,".",pass,LOGON32_LOGON_BATCH,
364 LOGON32_PROVIDER_DEFAULT,&hdl) ||
365 LogonUser (user,".",pass,LOGON32_LOGON_SERVICE,
366 LOGON32_PROVIDER_DEFAULT,&hdl)) &&
367 ImpersonateLoggedOnUser (hdl)) return env_init (user,NIL);
368 }
369 else { /* Win9x: done if from authserver_login() */
370 if (!pass) server_nli = NIL;
371 /* otherwise check MD5 database */
372 else if (s = auth_md5_pwd (user)) {
373 /* change NLI state based on pwd match */
374 server_nli = strcmp (s,pass);
375 memset (s,0,strlen (s));/* erase sensitive information */
376 fs_give ((void **) &s); /* flush erased password */
377 }
378 /* success if no longer NLI */
379 if (!server_nli) return env_init (user,NIL);
380 }
381 }
382 s = (logtry-- > 0) ? "Login failure" : "Excessive login attempts";
383 /* note the failure in the syslog */
384 syslog (LOG_INFO,"%s user=%.80s host=%.80s",s,user,tcp_clienthost ());
385 sleep (3); /* slow down possible cracker */
386 return NIL;
387 }
389 /* Authenticated server log in
390 * Accepts: user name string
391 * authentication user name string
392 * argument count
393 * argument vector
394 * Returns: T if password validated, NIL otherwise
395 */
397 long authserver_login (char *user,char *authuser,int argc,char *argv[])
398 {
399 return server_login (user,NIL,authuser,argc,argv);
400 }
403 /* Log in as anonymous daemon
404 * Accepts: argument count
405 * argument vector
406 * Returns: T if successful, NIL if error
407 */
409 long anonymous_login (int argc,char *argv[])
410 {
411 return server_login ("Guest",NIL,NIL,argc,argv);
412 }
415 /* Initialize environment
416 * Accepts: user name
417 * home directory, or NIL to use default
418 * Returns: T, always
419 */
421 long env_init (char *user,char *home)
422 {
423 /* don't init if blocked */
424 if (block_env_init) return LONGT;
425 if (myUserName) fatal ("env_init called twice!");
426 myUserName = cpystr (user); /* remember user name */
427 if (!myHomeDir) /* only if home directory not set up yet */
428 myHomeDir = (home && *home) ? cpystr (home) : win_homedir (user);
429 return T;
430 }
432 /* Check if NT
433 * Returns: T if NT, NIL if Win9x
434 */
436 int check_nt (void)
437 {
438 if (is_nt < 0) { /* not yet set up? */
439 OSVERSIONINFO ver;
440 ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
441 GetVersionEx (&ver);
442 is_nt = (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) ? T : NIL;
443 }
444 return is_nt;
445 }
448 /* Return Windows home directory
449 * Accepts: user name
450 * Returns: home directory
451 */
453 char *win_homedir (char *user)
454 {
455 char *s,*t,tmp[MAILTMPLEN];
456 PUSER_INFO_1 ui;
457 /* Win9x default */
458 if (!check_nt ()) sprintf (tmp,"%s\\My Documents",defaultDrive ());
459 /* get from user info on NT */
460 else if ((netapi || (netapi = LoadLibrary ("netapi32.dll"))) &&
461 (getinfo ||
462 (getinfo = (GETINFO) GetProcAddress (netapi,"NetUserGetInfo"))) &&
463 MultiByteToWideChar (CP_ACP,0,user,strlen (user) + 1,
464 (WCHAR *) tmp,MAILTMPLEN) &&
465 !(*getinfo) (NIL,(LPWSTR) &tmp,1,(LPBYTE *) &ui) &&
466 WideCharToMultiByte (CP_ACP,0,ui->usri1_home_dir,-1,
467 tmp,MAILTMPLEN,NIL,NIL) && tmp[0]) {
468 /* make sure doesn't end with delimiter */
469 if ((*(s = tmp + strlen (tmp) - 1) == '\\') || (*s == '/')) *s = '\0';
470 }
471 /* no home dir, found Win2K user profile? */
472 else if ((s = getenv ("USERPROFILE")) && (t = strrchr (s,'\\'))) {
473 strncpy (tmp,s,t-s); /* copy up to user name */
474 sprintf (tmp+(t-s),"\\%.100s\\My Documents",user);
475 }
476 /* last resort NT default */
477 else sprintf (tmp,"%s\\users\\default",defaultDrive ());
478 return cpystr (tmp);
479 }
482 /* Return default drive
483 * Returns: default drive
484 */
486 static char *defaultDrive (void)
487 {
488 char *s = getenv ("SystemDrive");
489 return (s && *s) ? s : "C:";
490 }
492 /* Return my user name
493 * Accepts: pointer to optional flags
494 * Returns: my user name
495 */
497 char *myusername_full (unsigned long *flags)
498 {
499 UCHAR usr[MAILTMPLEN];
500 DWORD len = MAILTMPLEN;
501 char *user,*path,*d,*p,pth[MAILTMPLEN];
502 char *ret = "SYSTEM";
503 /* get user name if don't have it yet */
504 if (!myUserName && !server_nli &&
505 /* use callback, else logon name */
506 ((mailusername && (user = (char *) (*mailusername) ())) ||
507 (GetUserName (usr,&len) && _stricmp (user = (char *) usr,"SYSTEM")))) {
508 if (block_env_init) { /* don't env_init if blocked */
509 if (flags) *flags = MU_LOGGEDIN;
510 return user;
511 }
512 /* try HOMEPATH, then HOME */
513 if (p = getenv ("HOMEPATH"))
514 sprintf (path = pth,"%s%s",
515 (d = getenv ("HOMEDRIVE")) ? d : defaultDrive (),p);
516 else if (!(path = getenv ("HOME")))
517 sprintf (path = pth,"%s\\My Documents",defaultDrive ());
518 /* make sure doesn't end with delimiter */
519 if ((*(p = path + strlen (path) -1) == '\\') || (*p == '/')) *p = '\0';
520 env_init (user,path); /* initialize environment */
521 }
522 if (myUserName) { /* logged in? */
523 if (flags) /* Guest is an anonymous user */
524 *flags = _stricmp (myUserName,"Guest") ? MU_LOGGEDIN : MU_ANONYMOUS;
525 ret = myUserName; /* return user name */
526 }
527 else if (flags) *flags = MU_NOTLOGGEDIN;
528 return ret;
529 }
531 /* Return my local host name
532 * Returns: my local host name
533 */
535 char *mylocalhost (void)
536 {
537 if (!myLocalHost) {
538 char tmp[MAILTMPLEN];
539 if (!wsa_initted++) { /* init Windows Sockets */
540 WSADATA wsock;
541 if (WSAStartup (WINSOCK_VERSION,&wsock)) {
542 wsa_initted = 0;
543 return "random-pc"; /* try again later? */
544 }
545 }
546 myLocalHost = cpystr ((gethostname (tmp,MAILTMPLEN-1) == SOCKET_ERROR) ?
547 "random-pc" : tcp_canonical (tmp));
548 }
549 return myLocalHost;
550 }
552 /* Return my home directory name
553 * Returns: my home directory name
554 */
556 char *myhomedir ()
557 {
558 if (!myHomeDir) myusername ();/* initialize if first time */
559 return myHomeDir ? myHomeDir : "";
560 }
563 /* Return system standard INBOX
564 * Accepts: buffer string
565 */
567 char *sysinbox ()
568 {
569 char tmp[MAILTMPLEN];
570 if (!sysInbox) { /* initialize if first time */
571 if (check_nt ()) sprintf (tmp,MAILFILE,myUserName);
572 else sprintf (tmp,"%s\\INBOX",myhomedir ());
573 sysInbox = cpystr (tmp); /* system inbox is from mail spool */
574 }
575 return sysInbox;
576 }
579 /* Return mailbox directory name
580 * Accepts: destination buffer
581 * directory prefix
582 * name in directory
583 * Returns: file name or NIL if error
584 */
586 char *mailboxdir (char *dst,char *dir,char *name)
587 {
588 char tmp[MAILTMPLEN];
589 if (dir || name) { /* if either argument provided */
590 if (dir) {
591 if (strlen (dir) > NETMAXMBX) return NIL;
592 strcpy (tmp,dir); /* write directory prefix */
593 }
594 else tmp[0] = '\0'; /* otherwise null string */
595 if (name) {
596 if (strlen (name) > NETMAXMBX) return NIL;
597 strcat (tmp,name); /* write name in directory */
598 }
599 /* validate name, return its name */
600 if (!mailboxfile (dst,tmp)) return NIL;
601 }
602 else strcpy (dst,myhomedir());/* no arguments, wants home directory */
603 return dst; /* return the name */
604 }
606 /* Return mailbox file name
607 * Accepts: destination buffer
608 * mailbox name
609 * Returns: file name or empty string for driver-selected INBOX or NIL if error
610 */
612 char *mailboxfile (char *dst,char *name)
613 {
614 char homedev[3];
615 char *dir = myhomedir ();
616 if (dir[0] && isalpha (dir[0]) && (dir[1] == ':')) {
617 homedev[0] = dir[0]; /* copy home device */
618 homedev[1] = dir[1];
619 homedev[2] = '\0';
620 }
621 else homedev[0] = '\0'; /* ??no home device?? */
622 *dst = '\0'; /* default to empty string */
623 /* check for INBOX */
624 if (!compare_cstring (name,"INBOX"));
625 /* reject names with / */
626 else if (strchr (name,'/')) dst = NIL;
627 else switch (*name) {
628 case '#': /* namespace names */
629 if (((name[1] == 'u') || (name[1] == 'U')) &&
630 ((name[2] == 's') || (name[2] == 'S')) &&
631 ((name[3] == 'e') || (name[3] == 'E')) &&
632 ((name[4] == 'r') || (name[4] == 'R')) && (name[5] == '.')) {
633 /* copy user name to destination buffer */
634 for (dir = dst,name += 6; *name && (*name != '\\'); *dir++ = *name++);
635 *dir++ = '\0'; /* tie off user name */
636 /* look up homedir for user name */
637 if (dir = win_homedir (dst)) {
638 /* build resulting name */
639 sprintf (dst,"%s\\%s",dir,name);
640 fs_give ((void **) &dir);
641 }
642 else dst = NIL;
643 }
644 else dst = NIL; /* unknown namespace name */
645 break;
646 case '\\': /* absolute path on default drive? */
647 sprintf (dst,"%s%s",homedev,name);
648 break;
649 default: /* any other name */
650 if (name[1] == ':') { /* some other drive? */
651 if (name[2] == '\\') strcpy (dst,name);
652 else sprintf (dst,"%c:\\%s",name[0],name+2);
653 }
654 /* build home-directory relative name */
655 else sprintf (dst,"%s\\%s",dir,name);
656 }
657 return dst; /* return it */
658 }
660 /* Lock file name
661 * Accepts: return buffer for file name
662 * file name
663 * locking to be placed on file if non-NIL
664 * Returns: file descriptor of lock or -1 if error
665 */
667 int lockname (char *lock,char *fname,int op)
668 {
669 int ld;
670 char c,*s;
671 /* Win2K and Win98 have TEMP under windir */
672 if (!((s = lockdir (lock,getenv ("windir"),"TEMP")) ||
673 /* NT4, NT3.x and Win95 use one of these */
674 (s = lockdir (lock,getenv ("TEMP"),NIL)) ||
675 (s = lockdir (lock,getenv ("TMP"),NIL)) ||
676 (s = lockdir (lock,getenv ("TMPDIR"),NIL)) ||
677 /* try one of these */
678 (s = lockdir (lock,defaultDrive (),"WINNT\\TEMP")) ||
679 (s = lockdir (lock,defaultDrive (),"WINDOWS\\TEMP")) ||
680 /* C:\TEMP is last resort */
681 (s = lockdir (lock,defaultDrive (),"TEMP")))) {
682 mm_log ("Unable to find temporary directory",ERROR);
683 return -1;
684 }
685 /* generate file name */
686 while (c = *fname++) switch (c) {
687 case '/': case '\\': case ':':
688 *s++ = '!'; /* convert bad chars to ! */
689 break;
690 default:
691 *s++ = c;
692 break;
693 }
694 *s++ = c; /* tie off name */
695 /* get the lock */
696 if (((ld = open (lock,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) >= 0) && op)
697 flock (ld,op); /* apply locking function */
698 return ld; /* return locking file descriptor */
699 }
701 /* Build lock directory, check to see if it exists
702 * Accepts: return buffer for lock directory
703 * first part of possible name
704 * optional second part
705 * Returns: pointer to end of buffer if buffer has a good name, else NIL
706 */
708 char *lockdir (char *lock,char *first,char *last)
709 {
710 struct stat sbuf;
711 char c,*s;
712 if (first && *first) { /* first part must be non-NIL */
713 /* copy first part */
714 for (s = lock; c = *first++; *s++ = (c == '/') ? '\\' : c);
715 if (last && *last) { /* copy last part if specified */
716 /* write trailing \ in case not in first */
717 if (s[-1] != '\\') *s++ = '\\';
718 while (c = *last++) *s++ = (c == '/') ? '\\' : c;
719 }
720 if (s[-1] == '\\') --s; /* delete trailing \ if any */
721 *s = s[1] = '\0'; /* tie off name at this point */
722 if (!stat (lock,&sbuf)) { /* does the name exist? */
723 *s++ = '\\'; /* yes, reinstall trailing \ */
724 return s; /* return the name */
725 }
726 }
727 return NIL; /* failed */
728 }
731 /* Unlock file descriptor
732 * Accepts: file descriptor
733 * lock file name from lockfd()
734 */
736 void unlockfd (int fd,char *lock)
737 {
738 flock (fd,LOCK_UN); /* unlock it */
739 close (fd); /* close it */
740 }
743 /* Determine default prototype stream to user
744 * Accepts: type (NIL for create, T for append)
745 * Returns: default prototype stream
746 */
748 MAILSTREAM *default_proto (long type)
749 {
750 extern MAILSTREAM CREATEPROTO,APPENDPROTO;
751 return type ? &APPENDPROTO : &CREATEPROTO;
752 }
754 /* Default block notify routine
755 * Accepts: reason for calling
756 * data
757 * Returns: data
758 */
760 void *mm_blocknotify (int reason,void *data)
761 {
762 void *ret = data;
763 switch (reason) {
764 case BLOCK_SENSITIVE: /* entering sensitive code */
765 ret = (void *) alarm (0);
766 break;
767 case BLOCK_NONSENSITIVE: /* exiting sensitive code */
768 if ((unsigned int) data) alarm ((unsigned int) data);
769 break;
770 default: /* ignore all other reasons */
771 break;
772 }
773 return ret;
774 }

UW-IMAP'd extensions by yuuji