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