* Many spelling errors corrected by Jens Schleusener. Thank you!
[alpine.git] / imap / src / osdep / nt / yunchan.c
blob05c0326afcca6138160764997e23a231452dcd3e
1 /* ========================================================================
2 * Copyright 1988-2006 University of Washington
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
8 * http://www.apache.org/licenses/LICENSE-2.0
11 * ========================================================================
15 * Program: Unix compatibility routines
17 * Author: Mark Crispin
18 * Networks and Distributed Computing
19 * Computing & Communications
20 * University of Washington
21 * Administration Building, AG-44
22 * Seattle, WA 98195
23 * Internet: MRC@CAC.Washington.EDU
25 * Date: 14 September 1996
26 * Last Edited: November 7, 2015.
27 * Eduardo Chappa <chappa@gmx.com>
31 /* DEDICATION
33 * This file is dedicated to my dog, Unix, also known as Yun-chan and
34 * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast. Unix
35 * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
36 * a two-month bout with cirrhosis of the liver.
38 * He was a dear friend, and I miss him terribly.
40 * Lift a leg, Yunie. Luv ya forever!!!!
42 \f
43 /* Emulator for BSD flock() call
44 * Accepts: file descriptor
45 * operation bitmask
46 * Returns: 0 if successful, -1 if failure
49 /* Our friends in Redmond have decided that you can not write to any segment
50 * which has a shared lock. This screws up the shared-write mailbox drivers
51 * (mbx, mtx, and tenex). As a workaround, we'll only lock the first byte of
52 * the file, meaning that you can't write that byte shared.
53 * This behavior seems to be new as of NT 4.0.
56 int flock (int fd,int op)
58 HANDLE hdl = (HANDLE) _get_osfhandle (fd);
59 DWORD flags = (op & LOCK_NB) ? LOCKFILE_FAIL_IMMEDIATELY : 0;
60 OVERLAPPED offset = {NIL,NIL,0,0,NIL};
61 int ret = -1;
62 blocknotify_t bn = (blocknotify_t)
63 ((op & LOCK_NB) ? NIL : mail_parameters (NIL,GET_BLOCKNOTIFY,NIL));
64 if (hdl < 0) errno = EBADF; /* error in file descriptor */
65 else switch (op & ~LOCK_NB) { /* translate to LockFileEx() op */
66 case LOCK_EX: /* exclusive */
67 flags |= LOCKFILE_EXCLUSIVE_LOCK;
68 case LOCK_SH: /* shared */
69 if (!check_nt ()) return 0; /* always succeeds if not NT */
70 if (bn) (*bn) (BLOCK_FILELOCK,NIL);
71 /* bug for bug compatible with Unix */
72 UnlockFileEx (hdl,NIL,1,0,&offset);
73 /* lock the file as requested */
74 if (LockFileEx (hdl,flags,NIL,1,0,&offset)) ret = 0;
75 if (bn) (*bn) (BLOCK_NONE,NIL);
76 /* if failed */
77 if (ret) errno = (op & LOCK_NB) ? EAGAIN : EBADF;
78 break;
79 case LOCK_UN: /* unlock */
80 if (check_nt ()) UnlockFileEx (hdl,NIL,1,0,&offset);
81 ret = 0; /* always succeeds */
82 default: /* default */
83 errno = EINVAL; /* bad call */
84 break;
86 return ret;
89 /* Local storage */
91 static char *loghdr; /* log file header string */
92 static HANDLE loghdl = NIL; /* handle of event source */
94 /* Emulator for BSD syslog() routine
95 * Accepts: priority
96 * message
97 * parameters
100 void syslog (int priority,const char *message,...)
102 va_list args;
103 LPTSTR strs[2];
104 char tmp[MAILTMPLEN]; /* callers must be careful not to pop this */
105 unsigned short etype;
106 if (!check_nt ()) return; /* no-op on non-NT system */
107 /* default event source */
108 if (!loghdl) openlog ("c-client",LOG_PID,LOG_MAIL);
109 switch (priority) { /* translate UNIX type into NT type */
110 case LOG_ALERT:
111 etype = EVENTLOG_ERROR_TYPE;
112 break;
113 case LOG_INFO:
114 etype = EVENTLOG_INFORMATION_TYPE;
115 break;
116 default:
117 etype = EVENTLOG_WARNING_TYPE;
119 va_start (args,message); /* initialize vararg mechanism */
120 vsprintf (tmp,message,args); /* build message */
121 strs[0] = loghdr; /* write header */
122 strs[1] = tmp; /* then the message */
123 /* report the event */
124 ReportEvent (loghdl,etype,(unsigned short) priority,2000,NIL,2,0,strs,NIL);
125 va_end (args);
129 /* Emulator for BSD openlog() routine
130 * Accepts: identity
131 * options
132 * facility
135 void openlog (const char *ident,int logopt,int facility)
137 char tmp[MAILTMPLEN];
138 if (!check_nt ()) return; /* no-op on non-NT system */
139 if (loghdl) fatal ("Duplicate openlog()!");
140 loghdl = RegisterEventSource (NIL,ident);
141 sprintf (tmp,(logopt & LOG_PID) ? "%s[%d]" : "%s",ident,getpid ());
142 loghdr = cpystr (tmp); /* save header for later */
145 /* Copy Unix string with CRLF newlines
146 * Accepts: destination string
147 * pointer to size of destination string buffer
148 * source string
149 * length of source string
150 * Returns: length of copied string
153 unsigned long unix_crlfcpy (char **dst,unsigned long *dstl,char *src,
154 unsigned long srcl)
156 unsigned long i,j;
157 char *d = src;
158 /* count number of LF's in source string(s) */
159 for (i = srcl,j = 0; j < srcl; j++) if (*d++ == '\012') i++;
160 /* flush destination buffer if too small */
161 if (*dst && (i > *dstl)) fs_give ((void **) dst);
162 if (!*dst) { /* make a new buffer if needed */
163 *dst = (char *) fs_get ((*dstl = i) + 1);
164 if (dstl) *dstl = i; /* return new buffer length to main program */
166 d = *dst; /* destination string */
167 /* copy strings, inserting CR's before LF's */
168 while (srcl--) switch (*src) {
169 case '\015': /* unlikely carriage return */
170 *d++ = *src++; /* copy it and any succeeding linefeed */
171 if (srcl && *src == '\012') {
172 *d++ = *src++;
173 srcl--;
175 break;
176 case '\012': /* line feed? */
177 *d++ ='\015'; /* yes, prepend a CR, drop into default case */
178 default: /* ordinary character */
179 *d++ = *src++; /* just copy character */
180 break;
182 *d = '\0'; /* tie off destination */
183 return d - *dst; /* return length */
186 /* Length of Unix string after unix_crlfcpy applied
187 * Accepts: source string
188 * Returns: length of string
191 unsigned long unix_crlflen (STRING *s)
193 unsigned long pos = GETPOS (s);
194 unsigned long i = SIZE (s);
195 unsigned long j = i;
196 while (j--) switch (SNX (s)) {/* search for newlines */
197 case '\015': /* unlikely carriage return */
198 if (j && (CHR (s) == '\012')) {
199 SNX (s); /* eat the line feed */
200 j--;
202 break;
203 case '\012': /* line feed? */
204 i++;
205 default: /* ordinary character */
206 break;
208 SETPOS (s,pos); /* restore old position */
209 return i;
212 /* Undoubtedly, I'm going to regret these two routines in the future. I
213 * regret them now. Their purpose is to work around two problems in the
214 * VC++ 6.0 C library:
215 * (1) tmpfile() creates the file in the current directory instead of a
216 * temporary directory
217 * (2) tmpfile() and fclose() think that on NT systems, it works to unlink
218 * the file while it's still open, so there's no need for the _tmpfname
219 * hook at fclose(). Unfortunately, that doesn't work in Win2K.
220 * I would be delighted to have a better alternative.
222 /* So Visual Studio 2015 came along and it made a change to the FILE structure
223 * so it is not possible to use _tmpfname to store the name of the temporary
224 * file name, so we will introduce an internal management system to keep track
225 * of temporary files. E.Ch.
228 typedef struct win_file {
229 FILE *f;
230 char *name;
231 } WIN_FILE_S;
233 typedef struct wintmpfile {
234 WIN_FILE_S *wf; /* where memory is saved */
235 int size; /* size of array of allocated memory */
236 int total; /* total number of allocated members */
237 } TMP_WINFILE;
239 #define TMPFILE_NUM 5 /* increase every 5 files, if we need to */
240 TMP_WINFILE win_tmp;
241 int inited = 0;
243 void add_tmpfile(TMP_WINFILE *wtmp, FILE *f, char *name)
245 if(wtmp == NULL)
246 return;
248 if(wtmp->total % TMPFILE_NUM == 0){
249 wtmp->size += TMPFILE_NUM;
250 fs_resize((void **)&wtmp->wf, wtmp->size*sizeof(WIN_FILE_S));
253 wtmp->wf[wtmp->total].f = f;
254 wtmp->wf[wtmp->total++].name = name;
257 int get_pos_tmpfile(TMP_WINFILE *wtmp, FILE *f)
259 int i;
261 if(wtmp == NULL || wtmp->total == 0)
262 return -1;
264 for(i = 0; i < wtmp->total && wtmp->wf[i].f != f; i++);
266 return i == wtmp->total ? -1 : i;
269 /* remove the element in position pos from wtmp, all memory is freed before
270 * calling this function */
271 void remove_pos_tmpfile(TMP_WINFILE *wtmp, int pos)
273 int i;
275 if(wtmp == NULL || pos < 0 || pos >= wtmp->total)
276 return;
278 wtmp->total--;
279 for(i = pos; i < wtmp->total; i++){
280 wtmp->wf[i].f = wtmp->wf[i+1].f;
281 wtmp->wf[i].name = wtmp->wf[i+1].name;
283 wtmp->wf[wtmp->total].f = NIL;
284 wtmp->wf[wtmp->total].name = NIL;
286 if(wtmp->total % TMPFILE_NUM == 0){
287 wtmp->size -= TMPFILE_NUM;
288 fs_resize((void **)&wtmp->wf, wtmp->size*sizeof(WIN_FILE_S));
290 if(wtmp->size == 0)
291 inited = 0; /* restart */
294 #undef fclose /* use the real fclose() in close_file() */
296 /* Substitute for Microsoft's tmpfile() that uses the real temporary directory
297 * Returns: FILE structure if success, NIL if failure
300 FILE *create_tempfile (void)
302 FILE *ret = NIL;
303 char *s = _tempnam (getenv ("TEMP"),"msg");
305 if(inited == 0){ /* initialize, just in case */
306 memset((void *)&win_tmp, 0, sizeof(TMP_WINFILE));
307 inited++;
309 if (s) { /* if got temporary name... */
310 /* open file, and stash name on record of temp files */
311 if (ret = fopen (s,"w+b")) add_tmpfile(&win_tmp, ret, s);
312 else fs_give ((void **) &s);/* flush temporary string */
314 return ret;
318 /* Substitute for Microsoft's fclose() that always flushes _tmpfname
319 * Returns: FILE structure if success, NIL if failure
322 int close_file (FILE *stream)
324 int ret;
325 int pos = get_pos_tmpfile(&win_tmp, stream);
326 ret = fclose (stream); /* close the file */
327 if (pos >= 0) { /* was this a temporary file? */
328 unlink (win_tmp.wf[pos].name); /* if so, delete it */
329 fs_give ((void **) &win_tmp.wf[pos].name); /* and flush the name */
330 remove_pos_tmpfile(&win_tmp, pos);
332 return ret;
335 /* Get password from console
336 * Accepts: prompt
337 * Returns: password
340 #define PWDLEN 128 /* used by Linux */
342 char *getpass (const char *prompt)
344 static char pwd[PWDLEN];
345 int ch,i,done;
346 fputs (prompt,stderr); /* output prompt */
347 for (i = done = 0; !done; ) switch (ch = _getch()) {
348 case 0x03: /* CTRL/C stops program */
349 _exit (1);
350 case '\b': /* BACKSPACE erase previous character */
351 if (i) pwd[--i] = '\0';
352 break;
353 case '\n': case '\r': /* CR or LF terminates string */
354 done = 1;
355 break;
356 default: /* any other character is a pwd char */
357 if (i < (PWDLEN - 1)) pwd[i++] = ch;
358 break;
360 pwd[i] = '\0'; /* tie off string with null */
361 putchar ('\n'); /* echo newline */
362 return pwd;