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