summaryrefslogtreecommitdiff
path: root/pith/stream.h
blob: 9cfa0db9631d48f1a3c77e0aed36f8e081de2b49 (plain)
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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
/*
 * $Id: stream.h 768 2007-10-24 00:10:03Z hubert@u.washington.edu $
 *
 * ========================================================================
 * Copyright 2013-2020 Eduardo Chappa
 * Copyright 2006-2007 University of Washington
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * ========================================================================
 */

#ifndef PITH_STREAM_INCLUDED
#define PITH_STREAM_INCLUDED


#include "../pith/context.h"
#include "../pith/msgno.h"
#include "../pith/savetype.h"


#define	AOS_NONE	0x00		/* alredy_open_stream: no flag  */
#define	AOS_RW_ONLY	0x01		/* don't match readonly streams */

/* pine_mail_list flags */
#define	PML_IS_MOVE_MBOX	0x01


/*
 * The stream pool is where we keep pointers to open streams. Some of them are
 * actively being used, some are connected to a folder but aren't actively
 * in use, some are random temporary use streams left open for possible
 * re-use. Each open stream should be in the streams array, which is of
 * size nstream altogether. Streams which are not to be re-used (don't have
 * the flag SP_USEPOOL set) are in the array anyway.
 */

/*
 * Structure holds global information about the stream pool. The per-stream
 * information is stored in a PER_STREAM_S struct attached to each stream.
 */
typedef struct stream_pool {
    int          max_remstream;	/* max implicitly cached remote streams	*/
    int          nstream;	/* size of streams array 		*/
    MAILSTREAM **streams;	/* the array of streams in stream pool	*/
} SP_S;

/*
 * Pine's private per-stream data stored on the c-client's stream
 * spare pointer.
 */
typedef struct pine_per_stream_data {
    MSGNO_S      *msgmap;
    CONTEXT_S    *context;		/* context fldr was interpreted in */
    char         *fldr;			/* folder name, alloced copy   */
    unsigned long flags;
    unsigned long icache_flags;
    int           ref_cnt;
    long          new_mail_count;   /* new mail since the last new_mail check */
    long          mail_since_cmd;   /* new mail since last key pressed */
    long          expunge_count;
    long          first_unseen;
    long          recent_since_visited;
    int           check_cnt;
    time_t        first_status_change;
    time_t        last_ping;		/* Keeps track of when the last    */
					/* command was. The command wasn't */
					/* necessarily a ping.             */
    time_t        last_expunged_reaper;	/* Some IMAP commands defer the    */
					/* return of EXPUNGE responses.    */
					/* This is the time of the last    */
					/* command which did not defer.    */
    time_t        last_chkpnt_done;
    time_t        last_use_time;
    time_t        last_activity;
    imapuid_t     saved_uid_validity;
    imapuid_t     saved_uid_last;
    char         *saved_cur_msg_id;
    unsigned      unsorted_newmail:1;
    unsigned      need_to_rethread:1;
    unsigned      io_error_on_stream:1;
    unsigned      mail_box_changed:1;
    unsigned      viewing_a_thread:1;
    unsigned      dead_stream:1;
    unsigned      noticed_dead_stream:1;
    unsigned      closing:1;
} PER_STREAM_S;

/*
 * Complicated set of flags for stream pool cache.
 * LOCKED, PERMLOCKED, TEMPUSE, and USEPOOL are flags stored in the stream
 * flags of the PER_STREAM_S structure.
 *
 *     SP_LOCKED -- In use, don't re-use this.
 *                  That isn't a good description of SP_LOCKED. Every time
 *                  we pine_mail_open a stream it is SP_LOCKED and a ref_cnt
 *                  is incremented. Pine_mail_close decrements the ref_cnt
 *                  and unlocks it when we get to zero.
 * SP_PERMLOCKED -- Should always be kept open, like INBOX. Right now the
 *                  only significance of this is that the expunge_and_close
 *                  won't happen if this is set (like the way INBOX works).
 *                  If a stream is PERMLOCKED it should no doubt be LOCKED
 *                  as well (it isn't done implicitly in the tests).
 *      SP_INBOX -- This stream is open on the INBOX.
 *   SP_USERFLDR -- This stream was opened by the user explicitly, not
 *                  implicitly like would happen with a save or a remote
 *                  address book, etc.
 *   SP_FILTERED -- This stream was opened by the user explicitly and
 *                  filtered.
 *    SP_TEMPUSE -- If a stream is not SP_LOCKED, that says we can re-use
 *                  it if need be but we should prefer to use another unused
 *                  slot if there is one. If a stream is marked TEMPUSE we
 *                  should consider re-using it before we consider re-using
 *                  a stream which is not LOCKED but not marked TEMPUSE.
 *                  This flag is not only stored in the PER_STREAM_S flags,
 *                  it is also an input argument to sp_stream_get.
 *                  It may make sense to mark a stream both SP_LOCKED and
 *                  SP_TEMPUSE. That way, when we close the stream it will
 *                  be SP_TEMPUSE and more re-usable than if we didn't.
 *    SP_USEPOOL -- Passed to pine_mail_open, it means to consider the
 *                  stream pool when opening and to put it into the stream
 *                  pool after we open it. If this is not set when we open,
 *                  we do an honest open and an honest close when we close.
 *
 *  These flags are input flags to sp_stream_get.
 *       SP_MATCH -- We're looking for a stream that is already open on
 *                   this mailbox. This is good if we are reopening the
 *                   same mailbox we already had opened.
 *        SP_SAME -- We're looking for a stream that is open to the same
 *                   server. For example, we might want to do a STATUS
 *                   command or a DELETE. We could use any stream that
 *                   is already open for this. Unless SP_MATCH is also
 *                   set, this will not return exact matches. (For example,
 *                   it is a bad idea to do a STATUS command on an already
 *                   selected mailbox. There may be locking problems if you
 *                   try to delete a folder that is selected...)
 *     SP_TEMPUSE -- The checking for SP_SAME streams is controlled by these
 *    SP_UNLOCKED    two flags. If SP_TEMPUSE is set then we will only match
 *                   streams which are marked TEMPUSE and not LOCKED.
 *                   If TEMPUSE is not set but UNLOCKED is, then we will
 *                   match on any same stream that is not locked. We'll choose
 *                   SP_TEMPUSE streams in preference to those that aren't
 *                   SP_TEMPUSE. If neither SP_TEMPUSE or SP_UNLOCKED is set,
 *                   then we'll consider any stream, even if it is locked.
 *                   We'll still prefer TEMPUSE first, then UNLOCKED, then any.
 *
 * Careful with the values of these flags. Some of them should really be
 * in separate name spaces, but we've combined all of them for convenience.
 * In particular, SP_USERFLDR, SP_INBOX, SP_USEPOOL, and SP_TEMPUSE are
 * all passed in the pine_mail_open flags argument, alongside OP_DEBUG and
 * friends from c-client. So they have to have different values than
 * those OP_ flags. SP_PERMLOCKED was passed at one time but isn't anymore.
 * Still, include it in the careful set. C-client reserves the bits
 * 0xff000000 for client flags.
 */

#define SP_USERFLDR	0x01000000
#define SP_INBOX	0x02000000
#define SP_USEPOOL	0x04000000
#define SP_TEMPUSE	0x08000000

#define SP_PERMLOCKED	0x10000000
#define SP_LOCKED	0x20000000

#define SP_MATCH	0x00100000
#define SP_SAME		0x00200000
#define SP_UNLOCKED	0x00400000
#define SP_FILTERED	0x00800000
#define SP_RO_OK	0x01000000	/* Readonly stream ok for SP_MATCH */

/* these are for icache_flags */
#define SP_NEED_FORMAT_SETUP         0x01
#define SP_FORMAT_INCLUDES_MSGNO     0x02
#define SP_FORMAT_INCLUDES_SMARTDATE 0x04


/* access value of first_unseen, but don't set it with this */
#define sp_first_unseen(stream)                                              \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->first_unseen : 0L)

/* use this to set it */
#define sp_set_first_unseen(stream,val) do{                                  \
		    if(sp_data(stream) && *sp_data(stream))                  \
		      (*sp_data(stream))->first_unseen = (val);}while(0)

#define sp_flags(stream)                                                     \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->flags : 0L)

#define sp_set_flags(stream,val) do{                                         \
		    if(sp_data(stream) && *sp_data(stream))                  \
		      (*sp_data(stream))->flags = (val);}while(0)

#define sp_icache_flags(stream)                                              \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->icache_flags : 0L)

#define sp_set_icache_flags(stream,val) do{                                  \
		    if(sp_data(stream) && *sp_data(stream))                  \
		      (*sp_data(stream))->icache_flags = (val);}while(0)

#define sp_ref_cnt(stream)                                                   \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->ref_cnt : 0L)

#define sp_set_ref_cnt(stream,val) do{                                       \
		    if(sp_data(stream) && *sp_data(stream))                  \
		      (*sp_data(stream))->ref_cnt = (val);}while(0)

#define sp_expunge_count(stream)                                             \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->expunge_count : 0L)

#define sp_set_expunge_count(stream,val) do{                                 \
		    if(sp_data(stream) && *sp_data(stream))                  \
		      (*sp_data(stream))->expunge_count = (val);}while(0)

#define sp_new_mail_count(stream)                                            \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->new_mail_count : 0L)

#define sp_set_new_mail_count(stream,val) do{                                \
		    if(sp_data(stream) && *sp_data(stream))                  \
		      (*sp_data(stream))->new_mail_count = (val);}while(0)

#define sp_mail_since_cmd(stream)                                            \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->mail_since_cmd : 0L)

#define sp_set_mail_since_cmd(stream,val) do{                                \
		    if(sp_data(stream) && *sp_data(stream))                  \
		      (*sp_data(stream))->mail_since_cmd = (val);}while(0)

#define sp_recent_since_visited(stream)                                      \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->recent_since_visited : 0L)

#define sp_set_recent_since_visited(stream,val) do{                          \
		    if(sp_data(stream) && *sp_data(stream))                  \
		      (*sp_data(stream))->recent_since_visited = (val);}while(0)

#define sp_check_cnt(stream)                                                 \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->check_cnt : 0L)

#define sp_set_check_cnt(stream,val) do{                                     \
		    if(sp_data(stream) && *sp_data(stream))                  \
		      (*sp_data(stream))->check_cnt = (val);}while(0)

#define sp_first_status_change(stream)                                      \
			    ((sp_data(stream) && *sp_data(stream))          \
			      ? (*sp_data(stream))->first_status_change : 0L)

#define sp_set_first_status_change(stream,val) do{                          \
		    if(sp_data(stream) && *sp_data(stream))                 \
		      (*sp_data(stream))->first_status_change = (val);}while(0)

#define sp_last_ping(stream)                                                \
			    ((sp_data(stream) && *sp_data(stream))          \
			      ? (*sp_data(stream))->last_ping : 0L)

#define sp_set_last_ping(stream,val) do{                                    \
		    if(sp_data(stream) && *sp_data(stream))                 \
		      (*sp_data(stream))->last_ping = (val);}while(0)

#define sp_last_expunged_reaper(stream)                                     \
			    ((sp_data(stream) && *sp_data(stream))          \
			      ? (*sp_data(stream))->last_expunged_reaper : 0L)

#define sp_set_last_expunged_reaper(stream,val) do{                         \
		    if(sp_data(stream) && *sp_data(stream))                 \
		      (*sp_data(stream))->last_expunged_reaper = (val);}while(0)

#define sp_last_chkpnt_done(stream)                                         \
			    ((sp_data(stream) && *sp_data(stream))          \
			      ? (*sp_data(stream))->last_chkpnt_done : 0L)

#define sp_set_last_chkpnt_done(stream,val) do{                             \
		    if(sp_data(stream) && *sp_data(stream))                 \
		      (*sp_data(stream))->last_chkpnt_done = (val);}while(0)

#define sp_last_use_time(stream)                                            \
			    ((sp_data(stream) && *sp_data(stream))          \
			      ? (*sp_data(stream))->last_use_time : 0L)

#define sp_set_last_use_time(stream,val) do{                                \
		    if(sp_data(stream) && *sp_data(stream))                 \
		      (*sp_data(stream))->last_use_time = (val);}while(0)

#define sp_last_activity(stream)                                            \
			    ((sp_data(stream) && *sp_data(stream))          \
			      ? (*sp_data(stream))->last_activity : 0L)

#define sp_set_last_activity(stream,val) do{                                \
		    if(sp_data(stream) && *sp_data(stream))                 \
		      (*sp_data(stream))->last_activity = (val);}while(0)

#define sp_saved_uid_validity(stream)                                        \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->saved_uid_validity : 0L)

#define sp_set_saved_uid_validity(stream,val) do{                            \
		    if(sp_data(stream) && *sp_data(stream))                  \
		     (*sp_data(stream))->saved_uid_validity = (val);}while(0)

#define sp_saved_uid_last(stream)                                            \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->saved_uid_last : 0L)

#define sp_set_saved_uid_last(stream,val) do{                                \
		    if(sp_data(stream) && *sp_data(stream))                  \
		     (*sp_data(stream))->saved_uid_last = (val);}while(0)

#define sp_mail_box_changed(stream)                                          \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->mail_box_changed : 0L)

#define sp_set_mail_box_changed(stream,val) do{                              \
		    if(sp_data(stream) && *sp_data(stream))                  \
		      (*sp_data(stream))->mail_box_changed = (val);}while(0)

#define sp_unsorted_newmail(stream)                                          \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->unsorted_newmail : 0L)

#define sp_set_unsorted_newmail(stream,val) do{                              \
		    if(sp_data(stream) && *sp_data(stream))                  \
		      (*sp_data(stream))->unsorted_newmail = (val);}while(0)

#define sp_need_to_rethread(stream)                                          \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->need_to_rethread : 0L)

#define sp_set_need_to_rethread(stream,val) do{                              \
		    if(sp_data(stream) && *sp_data(stream))                  \
		      (*sp_data(stream))->need_to_rethread = (val);}while(0)

#define sp_viewing_a_thread(stream)                                          \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->viewing_a_thread : 0L)

#define sp_set_viewing_a_thread(stream,val) do{                              \
		    if(sp_data(stream) && *sp_data(stream))                  \
		      (*sp_data(stream))->viewing_a_thread = (val);}while(0)

#define sp_dead_stream(stream)                                               \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->dead_stream : 0L)

#define sp_set_dead_stream(stream,val) do{                                   \
		    if(sp_data(stream) && *sp_data(stream))                  \
		      (*sp_data(stream))->dead_stream = (val);}while(0)

#define sp_noticed_dead_stream(stream)                                       \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->noticed_dead_stream : 0L)

#define sp_set_noticed_dead_stream(stream,val) do{                           \
		if(sp_data(stream) && *sp_data(stream))                      \
		  (*sp_data(stream))->noticed_dead_stream = (val);}while(0)

#define sp_closing(stream)                                                   \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->closing : 0L)

#define sp_set_closing(stream,val) do{                                       \
		    if(sp_data(stream) && *sp_data(stream))                  \
		      (*sp_data(stream))->closing = (val);}while(0)

#define sp_io_error_on_stream(stream)                                        \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->io_error_on_stream : 0L)

#define sp_set_io_error_on_stream(stream,val) do{                            \
		  if(sp_data(stream) && *sp_data(stream))                    \
		    (*sp_data(stream))->io_error_on_stream = (val);}while(0)

#define sp_fldr(stream)                                                      \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->fldr : (char *) NULL)

#define sp_saved_cur_msg_id(stream)                                          \
		    ((sp_data(stream) && *sp_data(stream))                   \
		      ? (*sp_data(stream))->saved_cur_msg_id : (char *) NULL)

#define sp_context(stream)                                                   \
			    ((sp_data(stream) && *sp_data(stream))           \
			      ? (*sp_data(stream))->context : 0L)

#define sp_set_context(stream,val) do{                                       \
		  if(sp_data(stream) && *sp_data(stream))                    \
		    (*sp_data(stream))->context = (val);}while(0)


extern MAILSTATUS *pine_cached_status;


/*
 * Macros to help fetch specific fields
 */
#define	pine_fetchheader_lines(S,N,M,F)	     pine_fetch_header(S,N,M,F,0L)
#define	pine_fetchheader_lines_not(S,N,M,F)  pine_fetch_header(S,N,M,F,FT_NOT)


/* exported prototypes */
MAILSTREAM    *pine_mail_open(MAILSTREAM *, char *, long, long *);
long	       pine_mail_create(MAILSTREAM *, char *);
long	       pine_mail_delete(MAILSTREAM *, char *);
long	       pine_mail_append_full(MAILSTREAM *, char *, char *, char *, STRING *);
#define pine_mail_append(stream,mailbox,message) \
   pine_mail_append_full(stream,mailbox,NULL,NULL,message)
long	       pine_mail_append_multiple(MAILSTREAM *, char *, append_t, APPENDPACKAGE *, MAILSTREAM *);
long	       pine_mail_copy_full(MAILSTREAM *, char *, char *, long);
#define pine_mail_copy(stream,sequence,mailbox) \
   pine_mail_copy_full(stream,sequence,mailbox,0)
long	       pine_mail_rename(MAILSTREAM *, char *, char *);
void	       pine_mail_close(MAILSTREAM *);
void	       pine_mail_actually_close(MAILSTREAM *);
void	       maybe_kill_old_stream(MAILSTREAM *);
long	       pine_mail_search_full(MAILSTREAM *, char *, SEARCHPGM *, long);
void	       pine_mail_fetch_flags(MAILSTREAM *, char *, long);
ENVELOPE      *pine_mail_fetchenvelope(MAILSTREAM *, unsigned long);
ENVELOPE      *pine_mail_fetch_structure(MAILSTREAM *, unsigned long, BODY **, long);
ENVELOPE      *pine_mail_fetchstructure(MAILSTREAM *, unsigned long, BODY **);
char	      *pine_mail_fetch_body(MAILSTREAM *, unsigned long, char *, unsigned long *, long);
char	      *pine_mail_fetch_text(MAILSTREAM *, unsigned long, char *, unsigned long *, long);
char	      *pine_mail_partial_fetch_wrapper(MAILSTREAM *, unsigned long, char *, unsigned long *,
					       long, unsigned long, char **, int);
long	       pine_mail_ping(MAILSTREAM *);
void	       pine_mail_check(MAILSTREAM *);
int	       pine_mail_list(MAILSTREAM *, char *, char *, unsigned *);
long	       pine_mail_status(MAILSTREAM *, char *, long);
long	       pine_mail_status_full(MAILSTREAM *, char *, long, imapuid_t *, imapuid_t *);
int	       check_for_move_mbox(char *, char *, size_t, char **);
MAILSTREAM    *already_open_stream(char *, int);
void	       pine_imap_cmd_happened(MAILSTREAM *, char *, long);
void	       sp_cleanup_dead_streams(void);
int	       sp_flagged(MAILSTREAM *, unsigned long);
void	       sp_set_fldr(MAILSTREAM *, char *);
void	       sp_set_saved_cur_msg_id(MAILSTREAM *, char *);
void	       sp_flag(MAILSTREAM *, unsigned long);
void	       sp_unflag(MAILSTREAM *, unsigned long);
void	       sp_mark_stream_dead(MAILSTREAM *);
int	       sp_nremote_permlocked(void);
MAILSTREAM    *sp_stream_get(char *, unsigned long);
void	       sp_end(void);
int	       sp_a_locked_stream_is_dead(void);
int	       sp_a_locked_stream_changed(void);
MAILSTREAM    *sp_inbox_stream(void);
PER_STREAM_S **sp_data(MAILSTREAM *);
MSGNO_S	      *sp_msgmap(MAILSTREAM *);
void	       sp_free_callback(void **);
MAILSTREAM    *same_stream(char *, MAILSTREAM *);
MAILSTREAM    *same_stream_and_mailbox(char *, MAILSTREAM *);
int	       same_remote_mailboxes(char *, char *);
int	       is_imap_stream(MAILSTREAM *);
int	       modern_imap_stream(MAILSTREAM *);
int	       streams_died(void);
int	       some_stream_is_locked(void);
void           appenduid_cb(char *mailbox,unsigned long uidvalidity, SEARCHSET *set);
imapuid_t      get_last_append_uid(void);
MAILSTREAM    *mail_cmd_stream(CONTEXT_S *, int *);
long           dummy_soutr(void *, char *);


#endif /* PITH_STREAM_INCLUDED */