/* 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 #include /* * 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. */ if (linkerr == EXDEV || linkerr == EPERM) { 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; } }