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