File: folder_addmsg.c

package info (click to toggle)
nmh 1.8-4
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 7,860 kB
  • sloc: ansic: 50,445; sh: 22,697; makefile: 1,138; lex: 740; perl: 509; yacc: 265
file content (207 lines) | stat: -rw-r--r-- 5,867 bytes parent folder | download | duplicates (3)
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;
    }
}