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