Removed unused local ncomps because gcc complained about it.
[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              */
170             if (linkerr == EXDEV) {
171                 if (stat (newmsg, &st1) == 0) {
172                     advise (NULL, "message %s:%s already exists", mp->foldpath, newmsg);
173                     return -1;
174                 } else {
175                     if ((infd = open (msgfile, O_RDONLY)) == -1) {
176                         advise (msgfile, "unable to open message %s", msgfile);
177                         return -1;
178                     }
179                     fstat (infd, &st1);
180                     if ((outfd = creat (newmsg, (int) st1.st_mode & 0777)) == -1) {
181                         advise (newmsg, "unable to create");
182                         close (infd);
183                         return -1;
184                     }
185                     cpydata (infd, outfd, msgfile, newmsg);
186                     close (infd);
187                     close (outfd);
188
189                     if (deleting) {
190                         (void)snprintf(oldmsg, sizeof (oldmsg), "%s/%s", from_dir, msgfile);
191                         (void)ext_hook("ref-hook", oldmsg, newmsg);
192                     }
193                     else
194                         (void)ext_hook("add-hook", newmsg, (char *)0);
195
196                     return msgnum;
197                 }
198             }
199
200             /*
201              * Else, some other type of link error,
202              * so just return error.
203              */
204             advise (newmsg, "error linking %s to", msgfile);
205             return -1;
206         }
207     }
208 }