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