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