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