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