Cleaned up test-utf8-body a bit.
[mmh] / sbr / folder_addmsg.c
1
2 /*
3  * folder_addmsg.c -- Link message into folder
4  *
5  * This code is Copyright (c) 2002, by the authors of nmh.  See the
6  * COPYRIGHT file in the root directory of the nmh distribution for
7  * complete copyright information.
8  */
9
10 #include <h/mh.h>
11 #include <fcntl.h>
12 #include <errno.h>
13
14 /*
15  * Link message into a folder.  Return the new number
16  * of the message.  If an error occurs, return -1.
17  */
18
19 int
20 folder_addmsg (struct msgs **mpp, char *msgfile, int selected,
21                int unseen, int preserve, int deleting, char *from_dir)
22 {
23     int infd, outfd, linkerr, msgnum;
24     char *nmsg, newmsg[BUFSIZ];
25     char oldmsg[BUFSIZ];
26     struct msgs *mp;
27     struct stat st1, st2;
28
29     mp = *mpp;
30
31     /* should we preserve the numbering of the message? */
32     if (preserve && (msgnum = m_atoi (msgfile)) > 0) {
33         ;
34     } else if (mp->nummsg == 0) {
35         /* check if we are adding to empty folder */
36         msgnum = 1;
37     } else {
38         /* else use highest message number + 1 */
39         msgnum = mp->hghmsg + 1;
40     }
41      
42     /*
43      * We might need to make several attempts
44      * in order to add the message to the folder.
45      */
46     for (;; msgnum++) {
47
48         /*
49          * See if we need more space.  If we need space at the
50          * end, then we allocate space for an addition 100 messages.
51          * If we need space at the beginning of the range, then just
52          * extend message status range to cover this message number.
53          */
54         if (msgnum > mp->hghoff) {
55             if ((mp = folder_realloc (mp, mp->lowoff, msgnum + 100)))
56                 *mpp = mp;
57             else {
58                 advise (NULL, "unable to allocate folder storage");
59                 return -1;
60             }
61         } else if (msgnum < mp->lowoff) {
62             if ((mp = folder_realloc (mp, msgnum, mp->hghoff)))
63                 *mpp = mp;
64             else {
65                 advise (NULL, "unable to allocate folder storage");
66                 return -1;
67             }
68         }
69
70         /*
71          * If a message is already in that slot,
72          * then loop to next available slot.
73          */
74         if (does_exist (mp, msgnum))
75             continue;
76
77         /* setup the bit flags for this message */
78         clear_msg_flags (mp, msgnum);
79         set_exists (mp, msgnum);
80
81         /* should we set the SELECT_UNSEEN bit? */
82         if (unseen) {
83             set_unseen (mp, msgnum);
84         }
85
86         /* should we set the SELECTED bit? */
87         if (selected) {
88             set_selected (mp, msgnum);
89
90             /* check if highest or lowest selected */
91             if (mp->numsel == 0) {
92                 mp->lowsel = msgnum;
93                 mp->hghsel = msgnum;
94             } else {
95                 if (msgnum < mp->lowsel)
96                     mp->lowsel = msgnum;
97                 if (msgnum > mp->hghsel)
98                     mp->hghsel = msgnum;
99             }
100
101             /* increment number selected */
102             mp->numsel++;
103         }
104
105         /*
106          * check if this is highest or lowest message
107          */
108         if (mp->nummsg == 0) {
109             mp->lowmsg = msgnum;
110             mp->hghmsg = msgnum;
111         } else {
112             if (msgnum < mp->lowmsg)
113                 mp->lowmsg = msgnum;
114             if (msgnum > mp->hghmsg)
115                 mp->hghmsg = msgnum;
116         }
117
118         /* increment message count */
119         mp->nummsg++;
120
121         nmsg = m_name (msgnum);
122         snprintf (newmsg, sizeof(newmsg), "%s/%s", mp->foldpath, nmsg);
123
124         /*
125          * Now try to link message into folder.
126          * Then run the external hook on the message if one was specified in the context.
127          * Run the refile hook if we're moving the message from one place to another.
128          * We have to construct the from path name for this because it's not there.
129          * Run the add hook if the message is getting copied or linked somewhere else.
130          */
131         if (link (msgfile, newmsg) != -1) {
132
133             if (deleting) {
134                 (void)snprintf(oldmsg, sizeof (oldmsg), "%s/%s", from_dir, msgfile);
135                 (void)ext_hook("ref-hook", oldmsg, newmsg);
136             }
137             else
138                 (void)ext_hook("add-hook", newmsg, (char *)0);
139
140             return msgnum;
141         } else {
142             linkerr = errno;
143
144 #ifdef EISREMOTE
145             if (linkerr == EISREMOTE)
146                 linkerr = EXDEV;
147 #endif /* EISREMOTE */
148
149             /*
150              * Check if the file in our desired location is the same
151              * as the source file.  If so, then just leave it alone
152              * and return.  Otherwise, we will continue the main loop
153              * and try again at another slot (hghmsg+1).
154              */
155             if (linkerr == EEXIST) {
156                 if (stat (msgfile, &st2) == 0 && stat (newmsg, &st1) == 0
157                     && st2.st_ino == st1.st_ino) {
158                     return msgnum;
159                 } else {
160                     continue;
161                 }
162             }
163
164             /*
165              * If link failed because we are trying to link
166              * across devices, then check if there is a message
167              * already in the desired location.  If so, then return
168              * error, else just copy the message.
169              * Cygwin with FAT32 filesystem produces EPERM.
170              */
171             if (linkerr == EXDEV  ||  linkerr == EPERM) {
172                 if (stat (newmsg, &st1) == 0) {
173                     advise (NULL, "message %s:%s already exists", mp->foldpath, newmsg);
174                     return -1;
175                 } else {
176                     if ((infd = open (msgfile, O_RDONLY)) == -1) {
177                         advise (msgfile, "unable to open message %s", msgfile);
178                         return -1;
179                     }
180                     fstat (infd, &st1);
181                     if ((outfd = creat (newmsg, (int) st1.st_mode & 0777)) == -1) {
182                         advise (newmsg, "unable to create");
183                         close (infd);
184                         return -1;
185                     }
186                     cpydata (infd, outfd, msgfile, newmsg);
187                     close (infd);
188                     close (outfd);
189
190                     if (deleting) {
191                         (void)snprintf(oldmsg, sizeof (oldmsg), "%s/%s", from_dir, msgfile);
192                         (void)ext_hook("ref-hook", oldmsg, newmsg);
193                     }
194                     else
195                         (void)ext_hook("add-hook", newmsg, (char *)0);
196
197                     return msgnum;
198                 }
199             }
200
201             /*
202              * Else, some other type of link error,
203              * so just return error.
204              */
205             advise (newmsg, "error linking %s to", msgfile);
206             return -1;
207         }
208     }
209 }