imapext-2007

diff src/dmail/dmail.c @ 0:ada5e610ab86

imap-2007e
author yuuji@gentei.org
date Mon, 14 Sep 2009 15:17:45 +0900
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/dmail/dmail.c	Mon Sep 14 15:17:45 2009 +0900
     1.3 @@ -0,0 +1,661 @@
     1.4 +/* ========================================================================
     1.5 + * Copyright 1988-2007 University of Washington
     1.6 + *
     1.7 + * Licensed under the Apache License, Version 2.0 (the "License");
     1.8 + * you may not use this file except in compliance with the License.
     1.9 + * You may obtain a copy of the License at
    1.10 + *
    1.11 + *     http://www.apache.org/licenses/LICENSE-2.0
    1.12 + *
    1.13 + * 
    1.14 + * ========================================================================
    1.15 + */
    1.16 +
    1.17 +/*
    1.18 + * Program:	Procmail-Callable Mail Delivery Module
    1.19 + *
    1.20 + * Author:	Mark Crispin
    1.21 + *		Networks and Distributed Computing
    1.22 + *		Computing & Communications
    1.23 + *		University of Washington
    1.24 + *		Administration Building, AG-44
    1.25 + *		Seattle, WA  98195
    1.26 + *		Internet: MRC@CAC.Washington.EDU
    1.27 + *
    1.28 + * Date:	5 April 1993
    1.29 + * Last Edited:	30 October 2008
    1.30 + */
    1.31 +
    1.32 +#include <stdio.h>
    1.33 +#include <pwd.h>
    1.34 +#include <errno.h>
    1.35 +extern int errno;		/* just in case */
    1.36 +#include <sysexits.h>
    1.37 +#include <sys/file.h>
    1.38 +#include <sys/stat.h>
    1.39 +#include "c-client.h"
    1.40 +#include "dquota.h"
    1.41 +
    1.42 +
    1.43 +/* Globals */
    1.44 +
    1.45 +char *version = "18";		/* dmail edit version */
    1.46 +int debug = NIL;		/* debugging (don't fork) */
    1.47 +int flagseen = NIL;		/* flag message as seen */
    1.48 +int trycreate = NIL;		/* flag saying gotta create before appending */
    1.49 +int critical = NIL;		/* flag saying in critical code */
    1.50 +char *sender = NIL;		/* message origin */
    1.51 +char *keywords = NIL;		/* keyword list */
    1.52 +long precedence = 0;		/* delivery precedence - used by quota hook */
    1.53 +
    1.54 +
    1.55 +/* Function prototypes */
    1.56 +
    1.57 +void file_string_init (STRING *s,void *data,unsigned long size);
    1.58 +char file_string_next (STRING *s);
    1.59 +void file_string_setpos (STRING *s,unsigned long i);
    1.60 +int main (int argc,char *argv[]);
    1.61 +int deliver (FILE *f,unsigned long msglen,char *user);
    1.62 +long ibxpath (MAILSTREAM *ds,char **mailbox,char *path);
    1.63 +int deliver_safely (MAILSTREAM *prt,STRING *st,char *mailbox,char *path,
    1.64 +		    char *tmp);
    1.65 +int delivery_unsafe (char *path,struct stat *sbuf,char *tmp);
    1.66 +int fail (char *string,int code);
    1.67 +
    1.68 +
    1.69 +/* File string driver for file stringstructs */
    1.70 +
    1.71 +STRINGDRIVER file_string = {
    1.72 +  file_string_init,		/* initialize string structure */
    1.73 +  file_string_next,		/* get next byte in string structure */
    1.74 +  file_string_setpos		/* set position in string structure */
    1.75 +};
    1.76 +
    1.77 +
    1.78 +/* Cache buffer for file stringstructs */
    1.79 +
    1.80 +#define CHUNKLEN 16384
    1.81 +char chunk[CHUNKLEN];
    1.82 +
    1.83 +/* Initialize file string structure for file stringstruct
    1.84 + * Accepts: string structure
    1.85 + *	    pointer to string
    1.86 + *	    size of string
    1.87 + */
    1.88 +
    1.89 +void file_string_init (STRING *s,void *data,unsigned long size)
    1.90 +{
    1.91 +  s->data = data;		/* note fd */
    1.92 +  s->size = size;		/* note size */
    1.93 +  s->chunk = chunk;
    1.94 +  s->chunksize = (unsigned long) CHUNKLEN;
    1.95 +  SETPOS (s,0);			/* set initial position */
    1.96 +}
    1.97 +
    1.98 +
    1.99 +/* Get next character from file stringstruct
   1.100 + * Accepts: string structure
   1.101 + * Returns: character, string structure chunk refreshed
   1.102 + */
   1.103 +
   1.104 +char file_string_next (STRING *s)
   1.105 +{
   1.106 +  char c = *s->curpos++;	/* get next byte */
   1.107 +  SETPOS (s,GETPOS (s));	/* move to next chunk */
   1.108 +  return c;			/* return the byte */
   1.109 +}
   1.110 +
   1.111 +
   1.112 +/* Set string pointer position for file stringstruct
   1.113 + * Accepts: string structure
   1.114 + *	    new position
   1.115 + */
   1.116 +
   1.117 +void file_string_setpos (STRING *s,unsigned long i)
   1.118 +{
   1.119 +  if (i > s->size) i = s->size;	/* don't permit setting beyond EOF */
   1.120 +  s->offset = i;		/* set new offset */
   1.121 +  s->curpos = s->chunk;		/* reset position */
   1.122 +				/* set size of data */
   1.123 +  if (s->cursize = min (s->chunksize,SIZE (s))) {
   1.124 +				/* move to that position in the file */
   1.125 +    fseek ((FILE *) s->data,s->offset,SEEK_SET);
   1.126 +    fread (s->curpos,sizeof (char),(unsigned int) s->cursize,(FILE *) s->data);
   1.127 +  }
   1.128 +}
   1.129 +
   1.130 +/* Main program */
   1.131 +
   1.132 +int main (int argc,char *argv[])
   1.133 +{
   1.134 +  FILE *f = NIL;
   1.135 +  int c,ret = 0;
   1.136 +  unsigned long msglen;
   1.137 +  char *s,tmp[MAILTMPLEN];
   1.138 +  uid_t ruid = getuid ();
   1.139 +  struct passwd *pwd = ruid ? getpwnam ("daemon") : NIL;
   1.140 +  openlog ("dmail",LOG_PID,LOG_MAIL);
   1.141 +				/* must not be root or daemon! */
   1.142 +  if (!ruid || (pwd && (pwd->pw_uid == ruid)))
   1.143 +    _exit (fail ("dmail may not be invoked by root or daemon",EX_USAGE));
   1.144 +#include "linkage.c"
   1.145 +				/* process all flags */
   1.146 +  for (--argc; argc && (*(s = *++argv)) == '-'; argc--) switch (s[1]) {
   1.147 +  case 'D':			/* debug */
   1.148 +    debug = T;			/* extra debugging */
   1.149 +    break;
   1.150 +  case 's':			/* deliver as seen */
   1.151 +    flagseen = T;
   1.152 +    break;
   1.153 +  case 'f':
   1.154 +  case 'r':			/* flag giving return path */
   1.155 +    if (sender) _exit (fail ("duplicate -r",EX_USAGE));
   1.156 +    if (argc--) sender = cpystr (*++argv);
   1.157 +    else _exit (fail ("missing argument to -r",EX_USAGE));
   1.158 +    break;
   1.159 +  case 'k':
   1.160 +    if (keywords) _exit (fail ("duplicate -k",EX_USAGE));
   1.161 +    if (argc--) keywords = cpystr (*++argv);
   1.162 +    else _exit (fail ("missing argument to -k",EX_USAGE));
   1.163 +    break;
   1.164 +  case 'p':
   1.165 +    if (s[2] && ((s[2] == '-') || isdigit (s[2]))) precedence = atol (s + 2);
   1.166 +    else if (argc-- && ((*(s = *++argv) == '-') || isdigit (*s)))
   1.167 +      precedence = atol (s);
   1.168 +    else _exit (fail ("missing argument to -p",EX_USAGE));
   1.169 +    break;
   1.170 +  default:			/* anything else */
   1.171 +    _exit (fail ("unknown switch",EX_USAGE));
   1.172 +  }
   1.173 +
   1.174 +  if (argc > 1) _exit (fail ("too many recipients",EX_USAGE));
   1.175 +  else if (!(f = tmpfile ())) _exit(fail ("can't make temp file",EX_TEMPFAIL));
   1.176 +				/* build delivery headers */
   1.177 +  if (sender) fprintf (f,"Return-Path: <%s>\015\012",sender);
   1.178 +				/* start Received line: */
   1.179 +  fprintf (f,"Received: via dmail-%s.%s for %s; ",CCLIENTVERSION,version,
   1.180 +	   (argc == 1) ? *argv : myusername ());
   1.181 +  rfc822_date (tmp);
   1.182 +  fputs (tmp,f);
   1.183 +  fputs ("\015\012",f);
   1.184 +				/* copy text from standard input */
   1.185 +  if (!fgets (tmp,MAILTMPLEN-1,stdin) || !(s = strchr (tmp,'\n')) ||
   1.186 +      (s == tmp) || s[1]) _exit (fail ("bad first message line",EX_USAGE));
   1.187 +  else if (s[-1] == '\015') {	/* nuke leading "From " line */
   1.188 +    if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
   1.189 +	(tmp[3] != 'm') || (tmp[4] != ' ')) fputs (tmp,f);
   1.190 +    while ((c = getchar ()) != EOF) putc (c,f);
   1.191 +  }
   1.192 +  else {
   1.193 +    if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
   1.194 +	(tmp[3] != 'm') || (tmp[4] != ' ')) {
   1.195 +      *s++ = '\015';		/* overwrite NL with CRLF */
   1.196 +      *s++ = '\012';
   1.197 +      *s = '\0';		/* tie off string */
   1.198 +      fputs (tmp,f);		/* write line */
   1.199 +    }
   1.200 +  }
   1.201 +				/* copy text from standard input */
   1.202 +  while ((c = getchar ()) != EOF) {
   1.203 +				/* add CR if needed */
   1.204 +    if (c == '\012') putc ('\015',f);
   1.205 +    putc (c,f);
   1.206 +  }
   1.207 +  msglen = ftell (f);		/* size of message */
   1.208 +  fflush (f);			/* make sure all changes written out */
   1.209 +  if (ferror (f)) ret = fail ("error writing temp file",EX_TEMPFAIL);
   1.210 +  else if (!msglen) ret = fail ("empty message",EX_TEMPFAIL);
   1.211 +				/* single delivery */
   1.212 +  else ret = deliver (f,msglen,argc ? *argv : myusername ());
   1.213 +  fclose (f);			/* all done with temporary file */
   1.214 +  _exit (ret);			/* normal exit */
   1.215 +  return 0;			/* stupid gcc */
   1.216 +}
   1.217 +
   1.218 +/* Deliver message to recipient list
   1.219 + * Accepts: file description of message temporary file
   1.220 + *	    size of message temporary file in bytes
   1.221 + *	    recipient name
   1.222 + * Returns: NIL if success, else error code
   1.223 + */
   1.224 +
   1.225 +int deliver (FILE *f,unsigned long msglen,char *user)
   1.226 +{
   1.227 +  MAILSTREAM *ds = NIL;
   1.228 +  char *s,*mailbox,tmp[MAILTMPLEN],path[MAILTMPLEN];
   1.229 +  STRING st;
   1.230 +  struct stat sbuf;
   1.231 +				/* have a mailbox specifier? */
   1.232 +  if (mailbox = strchr (user,'+')) {
   1.233 +    *mailbox++ = '\0';		/* yes, tie off user name */
   1.234 +    if (!*mailbox || !compare_cstring ((unsigned char *) mailbox,"INBOX"))
   1.235 +      mailbox = NIL;		/* user+ and user+INBOX same as user */
   1.236 +  }
   1.237 +  if (!*user) user = myusername ();
   1.238 +  else if (strcmp (user,myusername ()))
   1.239 +    return fail ("can't deliver to other user",EX_CANTCREAT);
   1.240 +  sprintf (tmp,"delivering to %.80s+%.80s",user,mailbox ? mailbox : "INBOX");
   1.241 +  mm_dlog (tmp);
   1.242 +				/* prepare stringstruct */
   1.243 +  INIT (&st,file_string,(void *) f,msglen);
   1.244 +  if (mailbox) {		/* non-INBOX name */
   1.245 +    switch (mailbox[0]) {	/* make sure a valid name */
   1.246 +    default:			/* other names, try to deliver if not INBOX */
   1.247 +      if (!strstr (mailbox,"..") && !strstr (mailbox,"//") &&
   1.248 +	  !strstr (mailbox,"/~") && mailboxfile (path,mailbox) && path[0] &&
   1.249 +	  !deliver_safely (NIL,&st,mailbox,path,tmp)) return NIL;
   1.250 +    case '%': case '*':		/* wildcards not valid */
   1.251 +    case '/':			/* absolute path names not valid */
   1.252 +    case '~':			/* user names not valid */
   1.253 +      sprintf (tmp,"invalid mailbox name %.80s+%.80s",user,mailbox);
   1.254 +      mm_log (tmp,WARN);
   1.255 +      break;
   1.256 +    }
   1.257 +    mm_dlog ("retrying delivery to INBOX");
   1.258 +    SETPOS (&st,0);		/* rewind stringstruct just in case */
   1.259 +  }
   1.260 +
   1.261 +				/* no -I, resolve "INBOX" into path */
   1.262 +  if (mailboxfile (path,mailbox = "INBOX") && !path[0]) {
   1.263 +				/* clear box, get generic INBOX prototype */
   1.264 +    if (!(ds = mail_open (NIL,"INBOX",OP_PROTOTYPE)))
   1.265 +      fatal ("no INBOX prototype");
   1.266 +				/* standard system driver? */
   1.267 +    if (!strcmp (ds->dtb->name,"unix") || !strcmp (ds->dtb->name,"mmdf")) {
   1.268 +      strcpy (path,sysinbox ());/* use system INBOX */
   1.269 +      if (!lstat (path,&sbuf))	/* deliver to existing system INBOX */
   1.270 +	return deliver_safely (ds,&st,mailbox,path,tmp);
   1.271 +    }
   1.272 +    else {			/* other driver, try ~/INBOX */
   1.273 +      if ((mailboxfile (path,"&&&&&") == path) &&
   1.274 +	  (s = strstr (path,"&&&&&")) && strcpy (s,"INBOX") &&
   1.275 +	  !lstat (path,&sbuf)){	/* deliver to existing ~/INBOX */
   1.276 +	sprintf (tmp,"#driver.%s/INBOX",ds->dtb->name);
   1.277 +	return deliver_safely (ds,&st,cpystr (tmp),path,tmp);
   1.278 +      }
   1.279 +    }
   1.280 +				/* not dummy, deliver to driver imputed path */
   1.281 +    if (strcmp (ds->dtb->name,"dummy"))
   1.282 +      return (ibxpath (ds,&mailbox,path) && !lstat (path,&sbuf)) ?
   1.283 +	deliver_safely (ds,&st,mailbox,path,tmp) :
   1.284 +	  fail ("unable to resolve INBOX path",EX_CANTCREAT);
   1.285 +				/* dummy, empty imputed append path exist? */
   1.286 +    if (ibxpath (ds = default_proto (T),&mailbox,path) &&
   1.287 +	!lstat (path,&sbuf) && !sbuf.st_size)
   1.288 +      return deliver_safely (ds,&st,mailbox,path,tmp);
   1.289 +				/* impute path that we will create */
   1.290 +    if (!ibxpath (ds = default_proto (NIL),&mailbox,path))
   1.291 +      return fail ("unable to resolve INBOX",EX_CANTCREAT);
   1.292 +  }
   1.293 +				/* black box, must create, get create proto */
   1.294 +  else if (lstat (path,&sbuf)) ds = default_proto (NIL);
   1.295 +  else {			/* black box, existing file */
   1.296 +				/* empty file, get append prototype */
   1.297 +    if (!sbuf.st_size) ds = default_proto (T);
   1.298 +				/* non-empty, get prototype from its data */
   1.299 +    else if (!(ds = mail_open (NIL,"INBOX",OP_PROTOTYPE)))
   1.300 +      fatal ("no INBOX prototype");
   1.301 +				/* error if unknown format */
   1.302 +    if (!strcmp (ds->dtb->name,"phile"))
   1.303 +      return fail ("unknown format INBOX",EX_UNAVAILABLE);
   1.304 +				/* otherwise can deliver to it */
   1.305 +    return deliver_safely (ds,&st,mailbox,path,tmp);
   1.306 +  }
   1.307 +  sprintf (tmp,"attempting to create mailbox %.80s path %.80s",mailbox,path);
   1.308 +  mm_dlog (tmp);
   1.309 +				/* supplicate to the Evil One */
   1.310 +  if (!path_create (ds,path)) return fail ("can't create INBOX",EX_CANTCREAT);
   1.311 +  sprintf (tmp,"created %.80s",path);
   1.312 +  mm_dlog (tmp);
   1.313 +				/* deliver the message */
   1.314 +  return deliver_safely (ds,&st,mailbox,path,tmp);
   1.315 +}
   1.316 +
   1.317 +/* Resolve INBOX from driver prototype into mailbox name and filesystem path
   1.318 + * Accepts: driver prototype
   1.319 + * 	    pointer to mailbox name string pointer
   1.320 + *	    buffer to return mailbox path
   1.321 + * Returns: T if success, NIL if error
   1.322 + */
   1.323 +
   1.324 +long ibxpath (MAILSTREAM *ds,char **mailbox,char *path)
   1.325 +{
   1.326 +  char *s,tmp[MAILTMPLEN];
   1.327 +  long ret = T;
   1.328 +  if (!ds) return NIL;
   1.329 +  else if (!strcmp (ds->dtb->name,"unix") || !strcmp (ds->dtb->name,"mmdf"))
   1.330 +    strcpy (path,sysinbox ());	/* use system INBOX for unix and MMDF */
   1.331 +  else if (!strcmp (ds->dtb->name,"tenex"))
   1.332 +    ret = (mailboxfile (path,"mail.txt") == path) ? T : NIL;
   1.333 +  else if (!strcmp (ds->dtb->name,"mtx"))
   1.334 +    ret = (mailboxfile (path,"INBOX.MTX") == path) ? T : NIL;
   1.335 +  else if (!strcmp (ds->dtb->name,"mbox"))
   1.336 +    ret = (mailboxfile (path,"mbox") == path) ? T : NIL;
   1.337 +				/* better not be a namespace driver */
   1.338 +  else if (ds->dtb->flags & DR_NAMESPACE) return NIL;
   1.339 +				/* INBOX in home directory */
   1.340 +  else ret = ((mailboxfile (path,"&&&&&") == path) &&
   1.341 +	      (s = strstr (path,"&&&&&")) && strcpy (s,"INBOX")) ? T : NIL;
   1.342 +  if (ret) {			/* don't bother if lossage */
   1.343 +    sprintf (tmp,"#driver.%s/INBOX",ds->dtb->name);
   1.344 +    *mailbox = cpystr (tmp);	/* name of INBOX in this namespace */
   1.345 +  }
   1.346 +  return ret;
   1.347 +}
   1.348 +
   1.349 +/* Deliver safely
   1.350 + * Accepts: prototype stream to force mailbox format
   1.351 + *	    stringstruct of message temporary file or NIL for check only
   1.352 + *	    mailbox name
   1.353 + *	    filesystem path name
   1.354 + *	    scratch buffer for messages
   1.355 + * Returns: NIL if success, else error code
   1.356 + */
   1.357 +
   1.358 +int deliver_safely (MAILSTREAM *prt,STRING *st,char *mailbox,char *path,
   1.359 +		    char *tmp)
   1.360 +{
   1.361 +  struct stat sbuf;
   1.362 +  char *flags = NIL;
   1.363 +  int i = delivery_unsafe (path,&sbuf,tmp);
   1.364 +  if (i) return i;		/* give up now if delivery unsafe */
   1.365 +				/* directory, not file */
   1.366 +  if ((sbuf.st_mode & S_IFMT) == S_IFDIR) {
   1.367 +    if (sbuf.st_mode & 0001) {	/* listable directories may be worrisome */
   1.368 +      sprintf (tmp,"WARNING: directory %.80s is listable",path);
   1.369 +      mm_log (tmp,WARN);
   1.370 +    }
   1.371 +  }
   1.372 +  else {			/* file, not directory */
   1.373 +    if (sbuf.st_nlink != 1) {	/* multiple links may be worrisome */
   1.374 +      sprintf (tmp,"WARNING: multiple links to file %.80s",path);
   1.375 +      mm_log (tmp,WARN);
   1.376 +    }
   1.377 +    if (sbuf.st_mode & 0111) {	/* executable files may be worrisome */
   1.378 +      sprintf (tmp,"WARNING: file %.80s is executable",path);
   1.379 +      mm_log (tmp,WARN);
   1.380 +    }
   1.381 +  }
   1.382 +  if (sbuf.st_mode & 0002) {	/* public-write files may be worrisome */
   1.383 +    sprintf (tmp,"WARNING: file %.80s is publicly-writable",path);
   1.384 +    mm_log (tmp,WARN);
   1.385 +  }
   1.386 +  if (sbuf.st_mode & 0004) {	/* public-write files may be worrisome */
   1.387 +    sprintf (tmp,"WARNING: file %.80s is publicly-readable",path);
   1.388 +    mm_log (tmp,WARN);
   1.389 +  }
   1.390 +				/* check site-written quota procedure */
   1.391 +  if (!dmail_quota (st,path,tmp,sender,precedence))
   1.392 +    return fail (tmp,EX_CANTCREAT);
   1.393 +				/* so far, so good */
   1.394 +  sprintf (tmp,"%s appending to %.80s (%s %.80s)",
   1.395 +	   prt ? prt->dtb->name : "default",mailbox,
   1.396 +	   ((sbuf.st_mode & S_IFMT) == S_IFDIR) ? "directory" : "file",path);
   1.397 +  mm_dlog (tmp);
   1.398 +  if (keywords) {		/* any keywords requested? */
   1.399 +    if (flagseen) sprintf (flags = tmp,"\\Seen %.1000s",keywords);
   1.400 +    else flags = keywords;
   1.401 +  }
   1.402 +  else if (flagseen) flags = "\\Seen";
   1.403 +				/* do the append now! */
   1.404 +  if (!mail_append_full (prt,mailbox,flags,NIL,st)) {
   1.405 +    sprintf (tmp,"message delivery failed to %.80s",path);
   1.406 +    return fail (tmp,EX_CANTCREAT);
   1.407 +  }
   1.408 +				/* note success */
   1.409 +  sprintf (tmp,"delivered to %.80s",path);
   1.410 +  mm_log (tmp,NIL);
   1.411 +				/* make sure nothing evil this way comes */
   1.412 +  return delivery_unsafe (path,&sbuf,tmp);
   1.413 +}
   1.414 +
   1.415 +/* Verify that delivery is safe
   1.416 + * Accepts: path name
   1.417 + *	    stat buffer
   1.418 + *	    scratch buffer for messages
   1.419 + * Returns: NIL if delivery is safe, error code if unsafe
   1.420 + */
   1.421 +
   1.422 +int delivery_unsafe (char *path,struct stat *sbuf,char *tmp)
   1.423 +{
   1.424 +  u_short type;
   1.425 +  sprintf (tmp,"Verifying safe delivery to %.80s",path);
   1.426 +  mm_dlog (tmp);
   1.427 +				/* prepare message just in case */
   1.428 +  sprintf (tmp,"delivery to %.80s unsafe: ",path);
   1.429 +				/* unsafe if can't get its status */
   1.430 +  if (lstat (path,sbuf)) strcat (tmp,strerror (errno));
   1.431 +				/* check file type */
   1.432 +  else switch (sbuf->st_mode & S_IFMT) {
   1.433 +  case S_IFDIR:			/* directory is always OK */
   1.434 +    return NIL;
   1.435 +  case S_IFREG:			/* file is unsafe if setuid */
   1.436 +    if (sbuf->st_mode & S_ISUID) strcat (tmp,"setuid file");
   1.437 +				/* or setgid */
   1.438 +    else if (sbuf->st_mode & S_ISGID) strcat (tmp,"setgid file");
   1.439 +    else return NIL;		/* otherwise safe */
   1.440 +    break;
   1.441 +  case S_IFCHR: strcat (tmp,"character special"); break;
   1.442 +  case S_IFBLK: strcat (tmp,"block special"); break;
   1.443 +  case S_IFLNK: strcat (tmp,"symbolic link"); break;
   1.444 +  case S_IFSOCK: strcat (tmp,"socket"); break;
   1.445 +  default:
   1.446 +    sprintf (tmp + strlen (tmp),"file type %07o",(unsigned int) type);
   1.447 +  }
   1.448 +  return fail (tmp,EX_CANTCREAT);
   1.449 +}
   1.450 +
   1.451 +/* Report an error
   1.452 + * Accepts: string to output
   1.453 + */
   1.454 +
   1.455 +int fail (char *string,int code)
   1.456 +{
   1.457 +  mm_log (string,ERROR);	/* pass up the string */
   1.458 +  switch (code) {
   1.459 +#if T
   1.460 +  case EX_USAGE:
   1.461 +  case EX_OSERR:
   1.462 +  case EX_SOFTWARE:
   1.463 +  case EX_NOUSER:
   1.464 +  case EX_CANTCREAT:
   1.465 +    code = EX_TEMPFAIL;		/* coerce these to TEMPFAIL */
   1.466 +    break;
   1.467 +#endif
   1.468 +  case -1:			/* quota failure... */
   1.469 +    code = EX_CANTCREAT;	/* ...really returns this code */
   1.470 +    break;
   1.471 +  default:
   1.472 +    break;
   1.473 +  }
   1.474 +  return code;			/* error code to return */
   1.475 +}
   1.476 +
   1.477 +/* Co-routines from MAIL library */
   1.478 +
   1.479 +
   1.480 +/* Message matches a search
   1.481 + * Accepts: MAIL stream
   1.482 + *	    message number
   1.483 + */
   1.484 +
   1.485 +void mm_searched (MAILSTREAM *stream,unsigned long msgno)
   1.486 +{
   1.487 +  fatal ("mm_searched() call");
   1.488 +}
   1.489 +
   1.490 +
   1.491 +/* Message exists (i.e. there are that many messages in the mailbox)
   1.492 + * Accepts: MAIL stream
   1.493 + *	    message number
   1.494 + */
   1.495 +
   1.496 +void mm_exists (MAILSTREAM *stream,unsigned long number)
   1.497 +{
   1.498 +  fatal ("mm_exists() call");
   1.499 +}
   1.500 +
   1.501 +
   1.502 +/* Message expunged
   1.503 + * Accepts: MAIL stream
   1.504 + *	    message number
   1.505 + */
   1.506 +
   1.507 +void mm_expunged (MAILSTREAM *stream,unsigned long number)
   1.508 +{
   1.509 +  fatal ("mm_expunged() call");
   1.510 +}
   1.511 +
   1.512 +
   1.513 +/* Message flags update seen
   1.514 + * Accepts: MAIL stream
   1.515 + *	    message number
   1.516 + */
   1.517 +
   1.518 +void mm_flags (MAILSTREAM *stream,unsigned long number)
   1.519 +{
   1.520 +}
   1.521 +
   1.522 +/* Mailbox found
   1.523 + * Accepts: MAIL stream
   1.524 + *	    delimiter
   1.525 + *	    mailbox name
   1.526 + *	    mailbox attributes
   1.527 + */
   1.528 +
   1.529 +void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
   1.530 +{
   1.531 +  fatal ("mm_list() call");
   1.532 +}
   1.533 +
   1.534 +
   1.535 +/* Subscribed mailbox found
   1.536 + * Accepts: MAIL stream
   1.537 + *	    delimiter
   1.538 + *	    mailbox name
   1.539 + *	    mailbox attributes
   1.540 + */
   1.541 +
   1.542 +void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
   1.543 +{
   1.544 +  fatal ("mm_lsub() call");
   1.545 +}
   1.546 +
   1.547 +
   1.548 +/* Mailbox status
   1.549 + * Accepts: MAIL stream
   1.550 + *	    mailbox name
   1.551 + *	    mailbox status
   1.552 + */
   1.553 +
   1.554 +void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
   1.555 +{
   1.556 +  fatal ("mm_status() call");
   1.557 +}
   1.558 +
   1.559 +/* Notification event
   1.560 + * Accepts: MAIL stream
   1.561 + *	    string to log
   1.562 + *	    error flag
   1.563 + */
   1.564 +
   1.565 +void mm_notify (MAILSTREAM *stream,char *string,long errflg)
   1.566 +{
   1.567 +  char tmp[MAILTMPLEN];
   1.568 +  tmp[11] = '\0';		/* see if TRYCREATE */
   1.569 +  if (!strcmp (ucase (strncpy (tmp,string,11)),"[TRYCREATE]")) trycreate = T;
   1.570 +  mm_log (string,errflg);	/* just do mm_log action */
   1.571 +}
   1.572 +
   1.573 +
   1.574 +/* Log an event for the user to see
   1.575 + * Accepts: string to log
   1.576 + *	    error flag
   1.577 + */
   1.578 +
   1.579 +void mm_log (char *string,long errflg)
   1.580 +{
   1.581 +  if (trycreate)mm_dlog(string);/* debug logging only if trycreate in effect */
   1.582 +  else {			/* ordinary logging */
   1.583 +    fprintf (stderr,"%s\n",string);
   1.584 +    switch (errflg) {  
   1.585 +    case NIL:			/* no error */
   1.586 +      syslog (LOG_INFO,"%s",string);
   1.587 +      break;
   1.588 +    case PARSE:			/* parsing problem */
   1.589 +    case WARN:			/* warning */
   1.590 +      syslog (LOG_WARNING,"%s",string);
   1.591 +      break;
   1.592 +    case ERROR:			/* error */
   1.593 +    default:
   1.594 +      syslog (LOG_ERR,"%s",string);
   1.595 +      break;
   1.596 +    }
   1.597 +  }
   1.598 +}
   1.599 +
   1.600 +
   1.601 +/* Log an event to debugging telemetry
   1.602 + * Accepts: string to log
   1.603 + */
   1.604 +
   1.605 +void mm_dlog (char *string)
   1.606 +{
   1.607 +  if (debug) fprintf (stderr,"%s\n",string);
   1.608 +  syslog (LOG_DEBUG,"%s",string);
   1.609 +}
   1.610 +
   1.611 +/* Get user name and password for this host
   1.612 + * Accepts: parse of network mailbox name
   1.613 + *	    where to return user name
   1.614 + *	    where to return password
   1.615 + *	    trial count
   1.616 + */
   1.617 +
   1.618 +void mm_login (NETMBX *mb,char *username,char *password,long trial)
   1.619 +{
   1.620 +  fatal ("mm_login() call");
   1.621 +}
   1.622 +
   1.623 +
   1.624 +/* About to enter critical code
   1.625 + * Accepts: stream
   1.626 + */
   1.627 +
   1.628 +void mm_critical (MAILSTREAM *stream)
   1.629 +{
   1.630 +  critical = T;			/* note in critical code */
   1.631 +}
   1.632 +
   1.633 +
   1.634 +/* About to exit critical code
   1.635 + * Accepts: stream
   1.636 + */
   1.637 +
   1.638 +void mm_nocritical (MAILSTREAM *stream)
   1.639 +{
   1.640 +  critical = NIL;		/* note not in critical code */
   1.641 +}
   1.642 +
   1.643 +
   1.644 +/* Disk error found
   1.645 + * Accepts: stream
   1.646 + *	    system error code
   1.647 + *	    flag indicating that mailbox may be clobbered
   1.648 + * Returns: T if user wants to abort
   1.649 + */
   1.650 +
   1.651 +long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
   1.652 +{
   1.653 +  return T;
   1.654 +}
   1.655 +
   1.656 +
   1.657 +/* Log a fatal error event
   1.658 + * Accepts: string to log
   1.659 + */
   1.660 +
   1.661 +void mm_fatal (char *string)
   1.662 +{
   1.663 +  printf ("?%s\n",string);	/* shouldn't happen normally */
   1.664 +}

UW-IMAP'd extensions by yuuji