Merge from vendor branch BSDTAR:
[dragonfly.git] / crypto / heimdal-0.6.3 / appl / popper / pop_updt.c
1 /*
2  * Copyright (c) 1989 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6
7 #include <popper.h>
8 RCSID("$Id: pop_updt.c,v 1.19 1998/04/23 18:36:51 joda Exp $");
9
10 static char standard_error[] =
11     "Error error updating primary drop. Mailbox unchanged";
12
13 /* 
14  *  updt:   Apply changes to a user's POP maildrop
15  */
16
17 int
18 pop_updt (POP *p)
19 {
20     FILE                *   md;                     /*  Stream pointer for 
21                                                         the user's maildrop */
22     int                     mfd;                    /*  File descriptor for
23                                                         above */
24     char                    buffer[BUFSIZ];         /*  Read buffer */
25
26     MsgInfoList         *   mp;                     /*  Pointer to message 
27                                                         info list */
28     int                     msg_num;                /*  Current message 
29                                                         counter */
30     int                     status_written;         /*  Status header field 
31                                                         written */
32     int                     nchar;                  /* Bytes read/written */
33
34     long                    offset;                 /* New mail offset */
35
36     int                     blank_line;
37
38 #ifdef DEBUG
39     if (p->debug) {
40         pop_log(p,POP_DEBUG,"Performing maildrop update...");
41         pop_log(p,POP_DEBUG,"Checking to see if all messages were deleted");
42     }
43 #endif /* DEBUG */
44
45     if(IS_MAILDIR(p))
46         return pop_maildir_update(p);
47
48     if (p->msgs_deleted == p->msg_count) {
49         /* Truncate before close, to avoid race condition,  DO NOT UNLINK!
50            Another process may have opened,  and not yet tried to lock */
51         ftruncate ((int)fileno(p->drop),0);
52         fclose(p->drop) ;
53         return (POP_SUCCESS);
54     }
55
56 #ifdef DEBUG
57     if (p->debug) 
58         pop_log(p,POP_DEBUG,"Opening mail drop \"%s\"",p->drop_name);
59 #endif /* DEBUG */
60
61     /*  Open the user's real maildrop */
62     if ((mfd = open(p->drop_name,O_RDWR|O_CREAT,0600)) == -1 ||
63         (md = fdopen(mfd,"r+")) == NULL) {
64         return pop_msg(p,POP_FAILURE,standard_error);
65     }
66
67     /*  Lock the user's real mail drop */
68     if ( flock(mfd, LOCK_EX) == -1 ) {
69         fclose(md) ;
70         return pop_msg(p,POP_FAILURE, "flock: '%s': %s", p->temp_drop,
71                        strerror(errno));
72     }
73
74     /* Go to the right places */
75     offset = lseek((int)fileno(p->drop),0,SEEK_END) ; 
76
77     /*  Append any messages that may have arrived during the session 
78         to the temporary maildrop */
79     while ((nchar=read(mfd,buffer,BUFSIZ)) > 0)
80         if ( nchar != write((int)fileno(p->drop),buffer,nchar) ) {
81             nchar = -1;
82             break ;
83         }
84     if ( nchar != 0 ) {
85         fclose(md) ;
86         ftruncate((int)fileno(p->drop),(int)offset) ;
87         fclose(p->drop) ;
88         return pop_msg(p,POP_FAILURE,standard_error);
89     }
90
91     rewind(md);
92     lseek(mfd,0,SEEK_SET);
93     ftruncate(mfd,0) ;
94
95     /* Synch stdio and the kernel for the POP drop */
96     rewind(p->drop);
97     lseek((int)fileno(p->drop),0,SEEK_SET);
98
99     /*  Transfer messages not flagged for deletion from the temporary 
100         maildrop to the new maildrop */
101 #ifdef DEBUG
102     if (p->debug) 
103         pop_log(p,POP_DEBUG,"Creating new maildrop \"%s\" from \"%s\"",
104                 p->drop_name,p->temp_drop);
105 #endif /* DEBUG */
106
107     for (msg_num = 0; msg_num < p->msg_count; ++msg_num) {
108
109         int doing_body;
110
111         /*  Get a pointer to the message information list */
112         mp = &p->mlp[msg_num];
113
114         if (mp->flags & DEL_FLAG) {
115 #ifdef DEBUG
116             if(p->debug)
117                 pop_log(p,POP_DEBUG,
118                     "Message %d flagged for deletion.",mp->number);
119 #endif /* DEBUG */
120             continue;
121         }
122
123         fseek(p->drop,mp->offset,0);
124
125 #ifdef DEBUG
126         if(p->debug)
127             pop_log(p,POP_DEBUG,"Copying message %d.",mp->number);
128 #endif /* DEBUG */
129         blank_line = 1;
130         for(status_written = doing_body = 0 ;
131             fgets(buffer,MAXMSGLINELEN,p->drop);) {
132
133             if (doing_body == 0) { /* Header */
134
135                 /*  Update the message status */
136                 if (strncasecmp(buffer,"Status:",7) == 0) {
137                     if (mp->flags & RETR_FLAG)
138                         fputs("Status: RO\n",md);
139                     else
140                         fputs(buffer, md);
141                     status_written++;
142                     continue;
143                 }
144                 /*  A blank line signals the end of the header. */
145                 if (*buffer == '\n') {
146                     doing_body = 1;
147                     if (status_written == 0) {
148                         if (mp->flags & RETR_FLAG)
149                             fputs("Status: RO\n\n",md);
150                         else
151                             fputs("Status: U\n\n",md);
152                     }
153                     else fputs ("\n", md);
154                     continue;
155                 }
156                 /*  Save another header line */
157                 fputs (buffer, md);
158             } 
159             else { /* Body */ 
160                 if (blank_line && strncmp(buffer,"From ",5) == 0) break;
161                 fputs (buffer, md);
162                 blank_line = (*buffer == '\n');
163             }
164         }
165     }
166
167     /* flush and check for errors now!  The new mail will writen
168        without stdio,  since we need not separate messages */
169
170     fflush(md) ;
171     if (ferror(md)) {
172         ftruncate(mfd,0) ;
173         fclose(md) ;
174         fclose(p->drop) ;
175         return pop_msg(p,POP_FAILURE,standard_error);
176     }
177
178     /* Go to start of new mail if any */
179     lseek((int)fileno(p->drop),offset,SEEK_SET);
180
181     while((nchar=read((int)fileno(p->drop),buffer,BUFSIZ)) > 0)
182         if ( nchar != write(mfd,buffer,nchar) ) {
183             nchar = -1;
184             break ;
185         }
186     if ( nchar != 0 ) {
187         ftruncate(mfd,0) ;
188         fclose(md) ;
189         fclose(p->drop) ;
190         return pop_msg(p,POP_FAILURE,standard_error);
191     }
192
193     /*  Close the maildrop and empty temporary maildrop */
194     fclose(md);
195     ftruncate((int)fileno(p->drop),0);
196     fclose(p->drop);
197
198     return(pop_quit(p));
199 }