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