1 | |
---|
2 | /* |
---|
3 | * folder_addmsg.c -- Link message into folder |
---|
4 | * |
---|
5 | * $Id: folder_addmsg.c,v 1.1.1.1 1999-02-07 18:14:08 danw Exp $ |
---|
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 | } |
---|