2 * $Id: stream.h 768 2007-10-24 00:10:03Z hubert@u.washington.edu $
4 * ========================================================================
5 * Copyright 2013-2021 Eduardo Chappa
6 * Copyright 2006-2007 University of Washington
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * ========================================================================
17 #ifndef PITH_STREAM_INCLUDED
18 #define PITH_STREAM_INCLUDED
21 #include "../pith/context.h"
22 #include "../pith/msgno.h"
23 #include "../pith/savetype.h"
26 #define AOS_NONE 0x00 /* alredy_open_stream: no flag */
27 #define AOS_RW_ONLY 0x01 /* don't match readonly streams */
29 /* pine_mail_list flags */
30 #define PML_IS_MOVE_MBOX 0x01
34 * The stream pool is where we keep pointers to open streams. Some of them are
35 * actively being used, some are connected to a folder but aren't actively
36 * in use, some are random temporary use streams left open for possible
37 * re-use. Each open stream should be in the streams array, which is of
38 * size nstream altogether. Streams which are not to be re-used (don't have
39 * the flag SP_USEPOOL set) are in the array anyway.
43 * Structure holds global information about the stream pool. The per-stream
44 * information is stored in a PER_STREAM_S struct attached to each stream.
46 typedef struct stream_pool
{
47 int max_remstream
; /* max implicitly cached remote streams */
48 int nstream
; /* size of streams array */
49 MAILSTREAM
**streams
; /* the array of streams in stream pool */
53 * Pine's private per-stream data stored on the c-client's stream
56 typedef struct pine_per_stream_data
{
58 CONTEXT_S
*context
; /* context fldr was interpreted in */
59 char *fldr
; /* folder name, alloced copy */
61 unsigned long icache_flags
;
63 long new_mail_count
; /* new mail since the last new_mail check */
64 long mail_since_cmd
; /* new mail since last key pressed */
67 long recent_since_visited
;
69 time_t first_status_change
;
70 time_t last_ping
; /* Keeps track of when the last */
71 /* command was. The command wasn't */
72 /* necessarily a ping. */
73 time_t last_expunged_reaper
; /* Some IMAP commands defer the */
74 /* return of EXPUNGE responses. */
75 /* This is the time of the last */
76 /* command which did not defer. */
77 time_t last_chkpnt_done
;
80 imapuid_t saved_uid_validity
;
81 imapuid_t saved_uid_last
;
82 char *saved_cur_msg_id
;
83 unsigned unsorted_newmail
:1;
84 unsigned need_to_rethread
:1;
85 unsigned io_error_on_stream
:1;
86 unsigned mail_box_changed
:1;
87 unsigned viewing_a_thread
:1;
88 unsigned dead_stream
:1;
89 unsigned noticed_dead_stream
:1;
94 * Complicated set of flags for stream pool cache.
95 * LOCKED, PERMLOCKED, TEMPUSE, and USEPOOL are flags stored in the stream
96 * flags of the PER_STREAM_S structure.
98 * SP_LOCKED -- In use, don't re-use this.
99 * That isn't a good description of SP_LOCKED. Every time
100 * we pine_mail_open a stream it is SP_LOCKED and a ref_cnt
101 * is incremented. Pine_mail_close decrements the ref_cnt
102 * and unlocks it when we get to zero.
103 * SP_PERMLOCKED -- Should always be kept open, like INBOX. Right now the
104 * only significance of this is that the expunge_and_close
105 * won't happen if this is set (like the way INBOX works).
106 * If a stream is PERMLOCKED it should no doubt be LOCKED
107 * as well (it isn't done implicitly in the tests).
108 * SP_INBOX -- This stream is open on the INBOX.
109 * SP_USERFLDR -- This stream was opened by the user explicitly, not
110 * implicitly like would happen with a save or a remote
112 * SP_FILTERED -- This stream was opened by the user explicitly and
114 * SP_TEMPUSE -- If a stream is not SP_LOCKED, that says we can re-use
115 * it if need be but we should prefer to use another unused
116 * slot if there is one. If a stream is marked TEMPUSE we
117 * should consider re-using it before we consider re-using
118 * a stream which is not LOCKED but not marked TEMPUSE.
119 * This flag is not only stored in the PER_STREAM_S flags,
120 * it is also an input argument to sp_stream_get.
121 * It may make sense to mark a stream both SP_LOCKED and
122 * SP_TEMPUSE. That way, when we close the stream it will
123 * be SP_TEMPUSE and more re-usable than if we didn't.
124 * SP_USEPOOL -- Passed to pine_mail_open, it means to consider the
125 * stream pool when opening and to put it into the stream
126 * pool after we open it. If this is not set when we open,
127 * we do an honest open and an honest close when we close.
129 * These flags are input flags to sp_stream_get.
130 * SP_MATCH -- We're looking for a stream that is already open on
131 * this mailbox. This is good if we are reopening the
132 * same mailbox we already had opened.
133 * SP_SAME -- We're looking for a stream that is open to the same
134 * server. For example, we might want to do a STATUS
135 * command or a DELETE. We could use any stream that
136 * is already open for this. Unless SP_MATCH is also
137 * set, this will not return exact matches. (For example,
138 * it is a bad idea to do a STATUS command on an already
139 * selected mailbox. There may be locking problems if you
140 * try to delete a folder that is selected...)
141 * SP_TEMPUSE -- The checking for SP_SAME streams is controlled by these
142 * SP_UNLOCKED two flags. If SP_TEMPUSE is set then we will only match
143 * streams which are marked TEMPUSE and not LOCKED.
144 * If TEMPUSE is not set but UNLOCKED is, then we will
145 * match on any same stream that is not locked. We'll choose
146 * SP_TEMPUSE streams in preference to those that aren't
147 * SP_TEMPUSE. If neither SP_TEMPUSE or SP_UNLOCKED is set,
148 * then we'll consider any stream, even if it is locked.
149 * We'll still prefer TEMPUSE first, then UNLOCKED, then any.
151 * Careful with the values of these flags. Some of them should really be
152 * in separate name spaces, but we've combined all of them for convenience.
153 * In particular, SP_USERFLDR, SP_INBOX, SP_USEPOOL, and SP_TEMPUSE are
154 * all passed in the pine_mail_open flags argument, alongside OP_DEBUG and
155 * friends from c-client. So they have to have different values than
156 * those OP_ flags. SP_PERMLOCKED was passed at one time but isn't anymore.
157 * Still, include it in the careful set. C-client reserves the bits
158 * 0xff000000 for client flags.
161 #define SP_USERFLDR 0x01000000
162 #define SP_INBOX 0x02000000
163 #define SP_USEPOOL 0x04000000
164 #define SP_TEMPUSE 0x08000000
166 #define SP_PERMLOCKED 0x10000000
167 #define SP_LOCKED 0x20000000
169 #define SP_MATCH 0x00100000
170 #define SP_SAME 0x00200000
171 #define SP_UNLOCKED 0x00400000
172 #define SP_FILTERED 0x00800000
173 #define SP_RO_OK 0x01000000 /* Readonly stream ok for SP_MATCH */
175 /* these are for icache_flags */
176 #define SP_NEED_FORMAT_SETUP 0x01
177 #define SP_FORMAT_INCLUDES_MSGNO 0x02
178 #define SP_FORMAT_INCLUDES_SMARTDATE 0x04
181 /* access value of first_unseen, but don't set it with this */
182 #define sp_first_unseen(stream) \
183 ((sp_data(stream) && *sp_data(stream)) \
184 ? (*sp_data(stream))->first_unseen : 0L)
186 /* use this to set it */
187 #define sp_set_first_unseen(stream,val) do{ \
188 if(sp_data(stream) && *sp_data(stream)) \
189 (*sp_data(stream))->first_unseen = (val);}while(0)
191 #define sp_flags(stream) \
192 ((sp_data(stream) && *sp_data(stream)) \
193 ? (*sp_data(stream))->flags : 0L)
195 #define sp_set_flags(stream,val) do{ \
196 if(sp_data(stream) && *sp_data(stream)) \
197 (*sp_data(stream))->flags = (val);}while(0)
199 #define sp_icache_flags(stream) \
200 ((sp_data(stream) && *sp_data(stream)) \
201 ? (*sp_data(stream))->icache_flags : 0L)
203 #define sp_set_icache_flags(stream,val) do{ \
204 if(sp_data(stream) && *sp_data(stream)) \
205 (*sp_data(stream))->icache_flags = (val);}while(0)
207 #define sp_ref_cnt(stream) \
208 ((sp_data(stream) && *sp_data(stream)) \
209 ? (*sp_data(stream))->ref_cnt : 0L)
211 #define sp_set_ref_cnt(stream,val) do{ \
212 if(sp_data(stream) && *sp_data(stream)) \
213 (*sp_data(stream))->ref_cnt = (val);}while(0)
215 #define sp_expunge_count(stream) \
216 ((sp_data(stream) && *sp_data(stream)) \
217 ? (*sp_data(stream))->expunge_count : 0L)
219 #define sp_set_expunge_count(stream,val) do{ \
220 if(sp_data(stream) && *sp_data(stream)) \
221 (*sp_data(stream))->expunge_count = (val);}while(0)
223 #define sp_new_mail_count(stream) \
224 ((sp_data(stream) && *sp_data(stream)) \
225 ? (*sp_data(stream))->new_mail_count : 0L)
227 #define sp_set_new_mail_count(stream,val) do{ \
228 if(sp_data(stream) && *sp_data(stream)) \
229 (*sp_data(stream))->new_mail_count = (val);}while(0)
231 #define sp_mail_since_cmd(stream) \
232 ((sp_data(stream) && *sp_data(stream)) \
233 ? (*sp_data(stream))->mail_since_cmd : 0L)
235 #define sp_set_mail_since_cmd(stream,val) do{ \
236 if(sp_data(stream) && *sp_data(stream)) \
237 (*sp_data(stream))->mail_since_cmd = (val);}while(0)
239 #define sp_recent_since_visited(stream) \
240 ((sp_data(stream) && *sp_data(stream)) \
241 ? (*sp_data(stream))->recent_since_visited : 0L)
243 #define sp_set_recent_since_visited(stream,val) do{ \
244 if(sp_data(stream) && *sp_data(stream)) \
245 (*sp_data(stream))->recent_since_visited = (val);}while(0)
247 #define sp_check_cnt(stream) \
248 ((sp_data(stream) && *sp_data(stream)) \
249 ? (*sp_data(stream))->check_cnt : 0L)
251 #define sp_set_check_cnt(stream,val) do{ \
252 if(sp_data(stream) && *sp_data(stream)) \
253 (*sp_data(stream))->check_cnt = (val);}while(0)
255 #define sp_first_status_change(stream) \
256 ((sp_data(stream) && *sp_data(stream)) \
257 ? (*sp_data(stream))->first_status_change : 0L)
259 #define sp_set_first_status_change(stream,val) do{ \
260 if(sp_data(stream) && *sp_data(stream)) \
261 (*sp_data(stream))->first_status_change = (val);}while(0)
263 #define sp_last_ping(stream) \
264 ((sp_data(stream) && *sp_data(stream)) \
265 ? (*sp_data(stream))->last_ping : 0L)
267 #define sp_set_last_ping(stream,val) do{ \
268 if(sp_data(stream) && *sp_data(stream)) \
269 (*sp_data(stream))->last_ping = (val);}while(0)
271 #define sp_last_expunged_reaper(stream) \
272 ((sp_data(stream) && *sp_data(stream)) \
273 ? (*sp_data(stream))->last_expunged_reaper : 0L)
275 #define sp_set_last_expunged_reaper(stream,val) do{ \
276 if(sp_data(stream) && *sp_data(stream)) \
277 (*sp_data(stream))->last_expunged_reaper = (val);}while(0)
279 #define sp_last_chkpnt_done(stream) \
280 ((sp_data(stream) && *sp_data(stream)) \
281 ? (*sp_data(stream))->last_chkpnt_done : 0L)
283 #define sp_set_last_chkpnt_done(stream,val) do{ \
284 if(sp_data(stream) && *sp_data(stream)) \
285 (*sp_data(stream))->last_chkpnt_done = (val);}while(0)
287 #define sp_last_use_time(stream) \
288 ((sp_data(stream) && *sp_data(stream)) \
289 ? (*sp_data(stream))->last_use_time : 0L)
291 #define sp_set_last_use_time(stream,val) do{ \
292 if(sp_data(stream) && *sp_data(stream)) \
293 (*sp_data(stream))->last_use_time = (val);}while(0)
295 #define sp_last_activity(stream) \
296 ((sp_data(stream) && *sp_data(stream)) \
297 ? (*sp_data(stream))->last_activity : 0L)
299 #define sp_set_last_activity(stream,val) do{ \
300 if(sp_data(stream) && *sp_data(stream)) \
301 (*sp_data(stream))->last_activity = (val);}while(0)
303 #define sp_saved_uid_validity(stream) \
304 ((sp_data(stream) && *sp_data(stream)) \
305 ? (*sp_data(stream))->saved_uid_validity : 0L)
307 #define sp_set_saved_uid_validity(stream,val) do{ \
308 if(sp_data(stream) && *sp_data(stream)) \
309 (*sp_data(stream))->saved_uid_validity = (val);}while(0)
311 #define sp_saved_uid_last(stream) \
312 ((sp_data(stream) && *sp_data(stream)) \
313 ? (*sp_data(stream))->saved_uid_last : 0L)
315 #define sp_set_saved_uid_last(stream,val) do{ \
316 if(sp_data(stream) && *sp_data(stream)) \
317 (*sp_data(stream))->saved_uid_last = (val);}while(0)
319 #define sp_mail_box_changed(stream) \
320 ((sp_data(stream) && *sp_data(stream)) \
321 ? (*sp_data(stream))->mail_box_changed : 0L)
323 #define sp_set_mail_box_changed(stream,val) do{ \
324 if(sp_data(stream) && *sp_data(stream)) \
325 (*sp_data(stream))->mail_box_changed = (val);}while(0)
327 #define sp_unsorted_newmail(stream) \
328 ((sp_data(stream) && *sp_data(stream)) \
329 ? (*sp_data(stream))->unsorted_newmail : 0L)
331 #define sp_set_unsorted_newmail(stream,val) do{ \
332 if(sp_data(stream) && *sp_data(stream)) \
333 (*sp_data(stream))->unsorted_newmail = (val);}while(0)
335 #define sp_need_to_rethread(stream) \
336 ((sp_data(stream) && *sp_data(stream)) \
337 ? (*sp_data(stream))->need_to_rethread : 0L)
339 #define sp_set_need_to_rethread(stream,val) do{ \
340 if(sp_data(stream) && *sp_data(stream)) \
341 (*sp_data(stream))->need_to_rethread = (val);}while(0)
343 #define sp_viewing_a_thread(stream) \
344 ((sp_data(stream) && *sp_data(stream)) \
345 ? (*sp_data(stream))->viewing_a_thread : 0L)
347 #define sp_set_viewing_a_thread(stream,val) do{ \
348 if(sp_data(stream) && *sp_data(stream)) \
349 (*sp_data(stream))->viewing_a_thread = (val);}while(0)
351 #define sp_dead_stream(stream) \
352 ((sp_data(stream) && *sp_data(stream)) \
353 ? (*sp_data(stream))->dead_stream : 0L)
355 #define sp_set_dead_stream(stream,val) do{ \
356 if(sp_data(stream) && *sp_data(stream)) \
357 (*sp_data(stream))->dead_stream = (val);}while(0)
359 #define sp_noticed_dead_stream(stream) \
360 ((sp_data(stream) && *sp_data(stream)) \
361 ? (*sp_data(stream))->noticed_dead_stream : 0L)
363 #define sp_set_noticed_dead_stream(stream,val) do{ \
364 if(sp_data(stream) && *sp_data(stream)) \
365 (*sp_data(stream))->noticed_dead_stream = (val);}while(0)
367 #define sp_closing(stream) \
368 ((sp_data(stream) && *sp_data(stream)) \
369 ? (*sp_data(stream))->closing : 0L)
371 #define sp_set_closing(stream,val) do{ \
372 if(sp_data(stream) && *sp_data(stream)) \
373 (*sp_data(stream))->closing = (val);}while(0)
375 #define sp_io_error_on_stream(stream) \
376 ((sp_data(stream) && *sp_data(stream)) \
377 ? (*sp_data(stream))->io_error_on_stream : 0L)
379 #define sp_set_io_error_on_stream(stream,val) do{ \
380 if(sp_data(stream) && *sp_data(stream)) \
381 (*sp_data(stream))->io_error_on_stream = (val);}while(0)
383 #define sp_fldr(stream) \
384 ((sp_data(stream) && *sp_data(stream)) \
385 ? (*sp_data(stream))->fldr : (char *) NULL)
387 #define sp_saved_cur_msg_id(stream) \
388 ((sp_data(stream) && *sp_data(stream)) \
389 ? (*sp_data(stream))->saved_cur_msg_id : (char *) NULL)
391 #define sp_context(stream) \
392 ((sp_data(stream) && *sp_data(stream)) \
393 ? (*sp_data(stream))->context : 0L)
395 #define sp_set_context(stream,val) do{ \
396 if(sp_data(stream) && *sp_data(stream)) \
397 (*sp_data(stream))->context = (val);}while(0)
400 extern MAILSTATUS
*pine_cached_status
;
404 * Macros to help fetch specific fields
406 #define pine_fetchheader_lines(S,N,M,F) pine_fetch_header(S,N,M,F,0L)
407 #define pine_fetchheader_lines_not(S,N,M,F) pine_fetch_header(S,N,M,F,FT_NOT)
410 /* exported prototypes */
411 MAILSTREAM
*pine_mail_open(MAILSTREAM
*, char *, long, long *);
412 long pine_mail_create(MAILSTREAM
*, char *);
413 long pine_mail_delete(MAILSTREAM
*, char *);
414 long pine_mail_append_full(MAILSTREAM
*, char *, char *, char *, STRING
*);
415 #define pine_mail_append(stream,mailbox,message) \
416 pine_mail_append_full(stream,mailbox,NULL,NULL,message)
417 long pine_mail_append_multiple(MAILSTREAM
*, char *, append_t
, APPENDPACKAGE
*, MAILSTREAM
*);
418 long pine_mail_copy_full(MAILSTREAM
*, char *, char *, long);
419 #define pine_mail_copy(stream,sequence,mailbox) \
420 pine_mail_copy_full(stream,sequence,mailbox,0)
421 long pine_mail_rename(MAILSTREAM
*, char *, char *);
422 void pine_mail_close(MAILSTREAM
*);
423 void pine_mail_actually_close(MAILSTREAM
*);
424 void maybe_kill_old_stream(MAILSTREAM
*);
425 long pine_mail_search_full(MAILSTREAM
*, char *, SEARCHPGM
*, long);
426 void pine_mail_fetch_flags(MAILSTREAM
*, char *, long);
427 ENVELOPE
*pine_mail_fetchenvelope(MAILSTREAM
*, unsigned long);
428 ENVELOPE
*pine_mail_fetch_structure(MAILSTREAM
*, unsigned long, BODY
**, long);
429 ENVELOPE
*pine_mail_fetchstructure(MAILSTREAM
*, unsigned long, BODY
**);
430 char *pine_mail_fetch_body(MAILSTREAM
*, unsigned long, char *, unsigned long *, long);
431 char *pine_mail_fetch_text(MAILSTREAM
*, unsigned long, char *, unsigned long *, long);
432 char *pine_mail_partial_fetch_wrapper(MAILSTREAM
*, unsigned long, char *, unsigned long *,
433 long, unsigned long, char **, int);
434 long pine_mail_ping(MAILSTREAM
*);
435 void pine_mail_check(MAILSTREAM
*);
436 int pine_mail_list(MAILSTREAM
*, char *, char *, unsigned *);
437 long pine_mail_status(MAILSTREAM
*, char *, long);
438 long pine_mail_status_full(MAILSTREAM
*, char *, long, imapuid_t
*, imapuid_t
*);
439 int check_for_move_mbox(char *, char *, size_t, char **);
440 MAILSTREAM
*already_open_stream(char *, int);
441 void pine_imap_cmd_happened(MAILSTREAM
*, char *, long);
442 void sp_cleanup_dead_streams(void);
443 int sp_flagged(MAILSTREAM
*, unsigned long);
444 void sp_set_fldr(MAILSTREAM
*, char *);
445 void sp_set_saved_cur_msg_id(MAILSTREAM
*, char *);
446 void sp_flag(MAILSTREAM
*, unsigned long);
447 void sp_unflag(MAILSTREAM
*, unsigned long);
448 void sp_mark_stream_dead(MAILSTREAM
*);
449 int sp_nremote_permlocked(void);
450 MAILSTREAM
*sp_stream_get(char *, unsigned long);
452 int sp_a_locked_stream_is_dead(void);
453 int sp_a_locked_stream_changed(void);
454 MAILSTREAM
*sp_inbox_stream(void);
455 PER_STREAM_S
**sp_data(MAILSTREAM
*);
456 MSGNO_S
*sp_msgmap(MAILSTREAM
*);
457 void sp_free_callback(void **);
458 MAILSTREAM
*same_stream(char *, MAILSTREAM
*);
459 MAILSTREAM
*same_stream_and_mailbox(char *, MAILSTREAM
*);
460 int same_remote_mailboxes(char *, char *);
461 int is_imap_stream(MAILSTREAM
*);
462 int modern_imap_stream(MAILSTREAM
*);
463 int streams_died(void);
464 int some_stream_is_locked(void);
465 void appenduid_cb(char *mailbox
,unsigned long uidvalidity
, SEARCHSET
*set
);
466 imapuid_t
get_last_append_uid(void);
467 MAILSTREAM
*mail_cmd_stream(CONTEXT_S
*, int *);
468 long dummy_soutr(void *, char *);
471 #endif /* PITH_STREAM_INCLUDED */