]> diplodocus.org Git - nmh/blob - sbr/folder_addmsg.c
Bring these changes over from the branch.
[nmh] / sbr / folder_addmsg.c
1
2 /*
3 * folder_addmsg.c -- Link message into folder
4 *
5 * $Id$
6 *
7 * This code is Copyright (c) 2002, by the authors of nmh. See the
8 * COPYRIGHT file in the root directory of the nmh distribution for
9 * complete copyright information.
10 */
11
12 #include <h/mh.h>
13 #include <fcntl.h>
14 #include <errno.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)
24 {
25 int infd, outfd, linkerr, first_time, msgnum;
26 char *nmsg, newmsg[BUFSIZ];
27 struct msgs *mp;
28 struct stat st1, st2;
29
30 first_time = 1; /* this is first attempt */
31 mp = *mpp;
32
33 /*
34 * We might need to make several attempts
35 * in order to add the message to the folder.
36 */
37 for (;;) {
38 /*
39 * Get the message number we will attempt to add.
40 */
41 if (first_time) {
42 /* should we preserve the numbering of the message? */
43 if (preserve && (msgnum = m_atoi (msgfile)) > 0) {
44 ;
45 } else if (mp->nummsg == 0) {
46 /* check if we are adding to empty folder */
47 msgnum = 1;
48 } else {
49 /* else use highest message number + 1 */
50 msgnum = mp->hghmsg + 1;
51 }
52 first_time = 0;
53 } else {
54 /* another attempt, so try next higher message number */
55 msgnum++;
56 }
57
58 /*
59 * See if we need more space. If we need space at the
60 * end, then we allocate space for an addition 100 messages.
61 * If we need space at the beginning of the range, then just
62 * extend message status range to cover this message number.
63 */
64 if (msgnum > mp->hghoff) {
65 if ((mp = folder_realloc (mp, mp->lowoff, msgnum + 100)))
66 *mpp = mp;
67 else {
68 advise (NULL, "unable to allocate folder storage");
69 return -1;
70 }
71 } else if (msgnum < mp->lowoff) {
72 if ((mp = folder_realloc (mp, msgnum, mp->hghoff)))
73 *mpp = mp;
74 else {
75 advise (NULL, "unable to allocate folder storage");
76 return -1;
77 }
78 }
79
80 /*
81 * If a message is already in that slot,
82 * then loop to next available slot.
83 */
84 if (does_exist (mp, msgnum))
85 continue;
86
87 /* setup the bit flags for this message */
88 clear_msg_flags (mp, msgnum);
89 set_exists (mp, msgnum);
90
91 /* should we set the SELECT_UNSEEN bit? */
92 if (unseen) {
93 set_unseen (mp, msgnum);
94 }
95
96 /* should we set the SELECTED bit? */
97 if (selected) {
98 set_selected (mp, msgnum);
99
100 /* check if highest or lowest selected */
101 if (mp->numsel == 0) {
102 mp->lowsel = msgnum;
103 mp->hghsel = msgnum;
104 } else {
105 if (msgnum < mp->lowsel)
106 mp->lowsel = msgnum;
107 if (msgnum > mp->hghsel)
108 mp->hghsel = msgnum;
109 }
110
111 /* increment number selected */
112 mp->numsel++;
113 }
114
115 /*
116 * check if this is highest or lowest message
117 */
118 if (mp->nummsg == 0) {
119 mp->lowmsg = msgnum;
120 mp->hghmsg = msgnum;
121 } else {
122 if (msgnum < mp->lowmsg)
123 mp->lowmsg = msgnum;
124 if (msgnum > mp->hghmsg)
125 mp->hghmsg = msgnum;
126 }
127
128 /* increment message count */
129 mp->nummsg++;
130
131 nmsg = m_name (msgnum);
132 snprintf (newmsg, sizeof(newmsg), "%s/%s", mp->foldpath, nmsg);
133
134 /*
135 * Now try to link message into folder
136 */
137 if (link (msgfile, newmsg) != -1) {
138 return msgnum;
139 } else {
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 } else {
158 continue;
159 }
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 */
168 if (linkerr == EXDEV) {
169 if (stat (newmsg, &st1) == 0) {
170 advise (NULL, "message %s:%s already exists", newmsg);
171 return -1;
172 } else {
173 if ((infd = open (msgfile, O_RDONLY)) == -1) {
174 advise (msgfile, "unable to open message %s");
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 return msgnum;
187 }
188 }
189
190 /*
191 * Else, some other type of link error,
192 * so just return error.
193 */
194 advise (newmsg, "error linking %s to", msgfile);
195 return -1;
196 }
197 }
198 }