/* msgfncs.c */
#include "ml.h"
/*
* This takes a message header, extracts the subject, and builds a
* "reply" subject out of it. It does these things after
* looking for a beginning "re" string.
* something - add a "re" -> "Re: something"
* Re: something - Keep it.
* Re[n]: something - Junk the junk.
* Re: Re[n]: something - Junk the junk.
*
* Return string is allocated and must be free'd when no longer needed.
*/
#ifdef __STDC__
char *get_reply_subject(char *header)
#else
char *get_reply_subject(header)
char *header;
#endif
{
char *ret;
char *subject;
char *decode_subject;
char *decode_result;
char *first_text;
char *ptr;
if(header == NULL)
return(cpystr(EMPTYSTR));
subject = get_header_field_contents(HEADER_SUBJECT, header);
if(! subject)
return(cpystr(MLGetLocalized(XtNmsgNoReplySubject,MsgNoReplySubject)));
decode_subject = (char *) fs_get(strlen(subject) + 1);
*decode_subject = NUL_TERM;
ptr = subject;
while((decode_result = iso_decode(&ptr,FALSE)) != NULL) {
strcat(decode_subject,decode_result);
fs_give((void **) &decode_result);
}
fs_give((void **) &subject);
first_text = first_nonwhite(decode_subject);
if(*first_text == NUL_TERM) {
fs_give((void **) &decode_subject);
return(cpystr(MLGetLocalized(XtNmsgNoReplySubject,MsgNoReplySubject)));
}
ret = (char *) fs_get(strlen(first_text) + 32);
/* Hack to catch non-conformists */
if(strncasecmp(first_text,"re: re[",7) == STRMATCH)
first_text += 4;
if(strncasecmp(first_text,"re[",3) == STRMATCH) {
ptr = strchr(first_text + 3,']');
if(ptr) {
ptr ++;
if(*ptr == ':')
ptr ++;
sprintf(ret,"Re:%s",ptr);
}
else {
sprintf(ret,"Re: %s",first_text);
}
}
else {
if(strncasecmp(first_text,"re:",3) == STRMATCH) {
sprintf(ret,"Re:%s",first_text + 3);
}
else
sprintf(ret,"Re: %s", first_text);
}
fs_give((void **) &decode_subject);
return(ret);
}
#ifdef __STDC__
char *get_forward_subject(char *header)
#else
char *get_forward_subject(header)
char *header;
#endif
{
char *ret;
char *subject;
char *decode_result;
char *ptr;
char *buffer = NULL;
if(header == NULL)
return(cpystr(EMPTYSTR));
subject = get_header_field_contents(HEADER_SUBJECT, header);
if(! subject)
subject = cpystr(EMPTYSTR);
buffer = (char *) fs_get(strlen(subject) + 64);
ret = (char *) fs_get(strlen(subject) + 64);
*buffer = NUL_TERM;
ptr = subject;
while((decode_result = iso_decode(&ptr,FALSE)) != NULL) {
strcat(buffer,decode_result);
fs_give((void **) &decode_result);
}
sprintf(ret,MLGetLocalized(XtNstrForwardSubject,StrForwardSubject),buffer);
fs_give((void **) &subject);
fs_give((void **) &buffer);
return(ret);
}
#ifdef __STDC__
char *get_short_forward_line(char *header, int count)
#else
char *get_short_forward_line(header, count)
char *header;
int count;
#endif
{
char *ret;
char *subject;
char *from;
char *ptr;
char *decode_ret;
char *decode_result;
if(header == NULL)
return(cpystr(EMPTYSTR));
from = get_header_field_contents(HEADER_FROM, header);
if(! from)
from = cpystr(EMPTYSTR);
subject = get_header_field_contents(HEADER_SUBJECT, header);
if(! subject)
subject = cpystr(EMPTYSTR);
decode_ret = (char *) fs_get(strlen(subject) + 1);
*decode_ret = NUL_TERM;
ptr = subject;
while((decode_result = iso_decode(&ptr,FALSE)) != NULL) {
strcat(decode_ret,decode_result);
fs_give((void **) &decode_result);
}
ret = (char *) fs_get(strlen(from) + strlen(subject) + 64);
sprintf(ret,"\t%3d) %s\n\t\t[%-.64s]\n",count, from, decode_ret);
fs_give((void **) &from);
fs_give((void **) &subject);
fs_give((void **) &decode_ret);
return(ret);
}
#ifdef __STDC__
char *get_forward_text(char *text)
#else
char *get_forward_text(text)
char *text;
#endif
{
char *ret;
if(text == NULL)
return(cpystr(EMPTYSTR));
ret = (char *) fs_get(strlen(text) + 256);
strcpy(ret,MLGetLocalized(XtNstrBeginForward,StrBeginForward));
strcat(ret,text);
strcat(ret,MLGetLocalized(XtNstrEndForward,StrEndForward));
return(ret);
}
#ifdef __STDC__
char *get_short_header(char *header)
#else
char *get_short_header(header)
char *header;
#endif
{
int cnt = 0;
char *existing = NULL;
char *new = NULL;
char *tmp = NULL;
if((session->header_set == (char **) NULL) || (header == NULL))
return(cpystr(EMPTYSTR));
for(cnt = 0; session->header_set[cnt] != NULL; cnt ++) {
tmp = get_formatted_header_field(session->header_set[cnt], header);
if(tmp == NULL)
continue;
if(existing) {
new = (char *) fs_get(strlen(existing) + strlen(tmp) + 1);
strcpy(new,existing);
strcat(new,tmp);
fs_give((void **) &existing);
existing = new;
}
else
existing = cpystr(tmp);
fs_give((void **) &tmp);
}
return((existing) ? existing : cpystr(EMPTYSTR));
}
/*
* Matches "field" (case-insensitive, colon OR no colon on input) in the
* header, and returns the contents of the field, including continuation
* lines, but without any LF's. The field name is not returned, only the
* contents.
*/
#ifdef __STDC__
char *get_header_field_contents(char *field, char *header)
#else
char *get_header_field_contents(field,header)
char *field;
char *header;
#endif
{
char *ptr = header;
unsigned long len = strlen(field);
unsigned long fieldlen = 0;
Boolean match = FALSE;
char *ret = NULL;
if(! header)
return(ret);
while(*ptr) {
if(((strncasecmp(ptr,field,len)) == STRMATCH) &&
(((*(ptr + len)) == COLONCHAR)
|| ((*(ptr + (len - 1))) == COLONCHAR))) {
match = TRUE;
if((*(ptr + len)) == COLONCHAR)
ptr += len + 1;
else
ptr += len;
while(isspace(*ptr))
ptr ++;
break;
}
else {
while(*ptr) {
if(*ptr == LFCHAR) {
ptr ++;
break;
}
ptr ++;
}
}
}
if(match == TRUE) {
fieldlen = header_field_len(ptr);
ret = (char *) fs_get(fieldlen + 1);
strncpy(ret,ptr,fieldlen);
ret[fieldlen] = NUL_TERM;
striplf(ret);
tabtospace(ret);
}
return(ret);
}
/*
* Finds a given field in the header (case insensitive, no colon on input),
* and produces a suitable for display representation, with a pseudo tab
* stop after the field name is printed, but this is ignored if the field
* name is bigger than the tab length.
* The field contents includes continuation lines and all linefeeds. the only
* formatting done is the initial pseudo tab and expansion of encoded header
* text if the charset is one that is useable.
*/
#ifdef __STDC__
char *get_formatted_header_field(char *field, char *header)
#else
char *get_formatted_header_field(field,header)
char *field;
char *header;
#endif
{
char *ptr = header;
unsigned long len = strlen(field);
unsigned long fieldlen = 0;
Boolean match = FALSE;
char *ret = NULL;
char *firstwhite;
char *newret;
char *iso_out;
if(! header)
return(ret);
while(*ptr) {
if(((strncasecmp(ptr,field,len)) == STRMATCH) &&
((*(ptr + len)) == COLONCHAR)) {
match = TRUE;
break;
}
else {
while(*ptr) {
if(*ptr == LFCHAR) {
ptr ++;
break;
}
ptr ++;
}
}
}
if(match == TRUE) {
fieldlen = header_field_len(ptr);
ret = (char *) fs_get((2 * fieldlen) + (2 * HEADER_TAB_LEN));
firstwhite = strchr(ptr,COLONCHAR);
firstwhite ++;
if((firstwhite - ptr) < HEADER_TAB_LEN) {
strncpy(ret,ptr,firstwhite - ptr);
ret[firstwhite - ptr] = NUL_TERM;
strncat(ret,BLANK_STR,HEADER_TAB_LEN - (firstwhite - ptr));
ret[HEADER_TAB_LEN] = NUL_TERM;
strncat(ret,firstwhite,fieldlen - (firstwhite - ptr));
ret[fieldlen + (HEADER_TAB_LEN - (firstwhite - ptr))] = NUL_TERM;
}
else {
strncpy(ret,ptr,fieldlen);
ret[fieldlen] = NUL_TERM;
}
ptr = ret;
newret = (char *) fs_get(strlen(ret) + 1);
*newret = NUL_TERM;
while((iso_out = iso_decode(&ptr, TRUE)) != NULL) {
strcat(newret,iso_out);
fs_give((void **) &iso_out);
}
fs_give((void **) &ret);
ret = newret;
}
return(ret);
}
/*
* Assumes that str points to the beginning of a header field.
* It finds the end of the field (allowing for continuation lines)
* and returns the length. This is used by the functions to extract
* particular header fields.
*/
#ifdef __STDC__
unsigned long header_field_len(char *str)
#else
unsigned long header_field_len(str)
char *str;
#endif
{
unsigned long n = 0;
char *ptr;
for(ptr = str; *ptr ; ptr ++, n ++) {
if(*ptr == LFCHAR) {
if((*(ptr + 1) == TABCHAR) || (*(ptr + 1) == SPACECHAR))
continue;
else
break;
}
}
return(n + 1);
}
#ifdef __STDC__
void elt_to_tm(MESSAGECACHE *elt, struct tm *Tm)
#else
void elt_to_tm(elt, Tm)
MESSAGECACHE *elt;
struct tm *Tm;
#endif
{
if(elt) {
memset(Tm, 0, sizeof(struct tm));
Tm->tm_year = (elt->year + BASEYEAR) - 1900;
Tm->tm_mon = elt->month - 1;
Tm->tm_mday = elt->day;
Tm->tm_hour = elt->hours;
Tm->tm_min = elt->minutes;
Tm->tm_sec = elt->seconds;
Tm->tm_isdst = (-1); /* Unavailable */
}
return;
}
#ifdef __STDC__
char *ml_fetchfrom(Message *message)
#else
char *ml_fetchfrom(message)
Message *message;
#endif
{
ADDRESS *address;
char buffer[FILEBUFFLEN];
char *ptr;
char *decode_ret;
*buffer = NUL_TERM;
if(message->envelope->from != NULL) {
address = message->envelope->from;
while((address != NULL) && (address->host == NULL))
address = address->next;
if(address != NULL) {
if(address->personal == NULL)
sprintf(buffer,"%s@%s",address->mailbox,address->host);
else {
ptr = address->personal;
while((decode_ret = iso_decode(&ptr,FALSE)) != NULL) {
strcat(buffer,decode_ret);
fs_give((void **) &decode_ret);
}
}
}
}
return(cpystr(buffer));
}
/*
* make_view_line is now a wrapper for format_line
*/
#ifdef __STDC__
XmString make_view_line(Message *message)
#else
XmString make_view_line(message)
Message *message;
#endif
{
char buffer[FILEBUFFLEN];
format_line(message, buffer, preferences.viewline_format);
return(XmStringCreateSimple(buffer));
}
#ifdef __STDC__
void make_attribution_line(Message *message, char *buffer)
#else
void make_attribution_line(message,buffer)
Message *message;
char *buffer;
#endif
{
*buffer = '\0';
if (*preferences.attribution_format) {
format_line(message, buffer, preferences.attribution_format);
}
}
/*
* the original make_view_line function, genericised
* to get the format string as an argument
*/
#ifdef __STDC__
void format_line(Message *message, char *buffer, char *fmt)
#else
void format_line(message,buffer,fmt)
Message *message;
char *buffer;
char *fmt;
#endif
{
char mnum[32];
char date[256];
char size[32];
char flags[32];
char *type;
char *subject;
char *fix_subject;
char fmttmp[FILEBUFFLEN], raddrtmp[FILEBUFFLEN], saddrtmp[FILEBUFFLEN];
char *vln, *ref;
char *rpersonal, *ruser, *rhost, *spersonal, *suser, *shost;
int tomyself;
struct tm t;
MESSAGECACHE *elt;
XmString ret;
/* We have the info ?? */
if(message && message->longcache && message->envelope) {
elt = &(message->longcache->elt);
sprintf(mnum,"%lu",message->msgno);
flags[0] =
(elt->recent)
? ((elt->seen) ? 'R' : 'N'):
((elt->seen) ? ' ' : 'U');
flags[1] = (elt->flagged) ? 'F' : ' ';
flags[2] = (elt->answered) ? 'A' : ' ';
flags[3] = (elt->deleted) ? 'D' : ' ';
flags[4] = NUL_TERM;
if(message->sender == NULL)
message->sender = ml_fetchfrom(message);
if(message->body) {
if(message->body->type == TYPETEXT)
type = "T";
else
type = "M";
}
else
type = " ";
if(message->subject == NULL) {
subject = message->envelope->subject;
if(subject == NULL)
subject = EMPTYSTR;
message->subject = (char *) fs_get(strlen(subject) + 1);
*message->subject = NUL_TERM;
while((fix_subject = iso_decode(&subject,FALSE)) != NULL) {
strcat(message->subject,fix_subject);
fs_give((void **) &fix_subject);
}
}
/* View line format components
%D{format} define date format (for strftime)
%S subject
%n message number
%F flags
%T type
%L length
%P sender, personal name (if not known, substituted with %U@%H)
%U sender, user name
%H sender, host
%A sender, user@host
%p receiver, personal name (if not known, substituted with %u@%h)
%u receiver, user name
%h receiver, host
%a receiver, user@host
%M{sss} if sender matches current login name, use %p for %P, %u for %U,
%h for %H, %a for %A, and insert sss
%N{sss} if sender do not match current login name, insert sss
*/
rpersonal = (message->envelope && message->envelope->to
&& message->envelope->to->personal) ?
message->envelope->to->personal : NULL;
ruser = (message->envelope && message->envelope->to
&& message->envelope->to->mailbox) ?
message->envelope->to->mailbox : "";
rhost = (message->envelope && message->envelope->to
&& message->envelope->to->host) ?
message->envelope->to->host : "";
spersonal = message->sender;
shost = (message->envelope && message->envelope->from
&& message->envelope->from->host) ?
message->envelope->from->host : "";
suser = (message->envelope && message->envelope->from
&& message->envelope->from->mailbox) ?
message->envelope->from->mailbox : "";
sprintf(raddrtmp, "%s@%s", ruser, rhost);
sprintf(saddrtmp, "%s@%s", suser, shost);
if (!rpersonal)
rpersonal = raddrtmp;
if (!spersonal)
spersonal = saddrtmp;
tomyself = (message->sender && local_auth.fullname
&& (strcmp(message->sender, local_auth.fullname) == 0));
*buffer = '\0'; vln = buffer;
for (; *fmt;) {
char* ffmt = fmttmp;
if (*fmt == '%') {
if (*(fmt+2) == '{') {
char f = *(fmt+1);
fmt += 3;
while (*fmt && (*fmt != '}'))
*ffmt++ = *fmt++;
*ffmt++ = '\0';
fmt++;
switch (f) {
case 'M':
if (tomyself) {
spersonal = rpersonal;
suser = ruser;
shost = rhost;
strcpy(saddrtmp, raddrtmp);
}
else
*fmttmp = '\0';
break;
case 'N':
if (tomyself)
*fmttmp = '\0';
break;
case 'D':
elt_to_tm(elt,&t);
strftime(date,sizeof(date),fmttmp,&t);
strcpy(fmttmp, date);
break;
default:
break;
}
}
else {
*ffmt++ = *fmt++;
while (((*fmt >= '0') && (*fmt < '9'))
|| (*fmt == '-') || (*fmt == '.'))
*ffmt++ = *fmt++;
*ffmt++ = 's';
*ffmt = '\0';
switch (*fmt++) {
case 'D': ref = "Invalid use of %D flag"; break;
case 'n': ref = mnum; break;
case 'S': ref = message->subject; break;
case 'F': ref = flags; break;
case 'T': ref = type; break;
case 'L':
if(elt->rfc822_size > (1000000L * 1024L))
sprintf(size,"%luG",elt->rfc822_size / (1000000L * 1024L));
else
if(elt->rfc822_size > (1000L * 1024L))
sprintf(size,"%luM)",elt->rfc822_size / (1000L * 1024L));
else
if(elt->rfc822_size > (9L * 1024L))
sprintf(size,"%luK",elt->rfc822_size / (1024L));
else
sprintf(size,"%lu",elt->rfc822_size);
ref = size;
break;
case 'P': ref = spersonal; break;
case 'U': ref = suser; break;
case 'H': ref = shost; break;
case 'A': ref = saddrtmp; break;
case 'p': ref = rpersonal; break;
case 'u': ref = ruser; break;
case 'h': ref = rhost; break;
case 'a': ref = raddrtmp; break;
case 'M': ref = "Invalid use of %M flag"; break;
case '%': ref = "%"; break;
default:
ref = "<Unknown flag>";
}
}
sprintf(vln, fmttmp, ref);
vln += strlen(vln);
}
else
*vln++ = *fmt++;
}
}
else /* We don't have the info */
sprintf(buffer,MLGetLocalized(XtNmsgNotYetLoaded,MsgNotYetLoaded));
}
#ifdef __STDC__
char *byte_print(unsigned long size, char *buffer)
#else
char *byte_print(size, buffer)
unsigned long size;
char *buffer;
#endif
{
if(size > (1000000L * 1024L))
sprintf(buffer,"(%3luG)", size / (1000000L * 1024L));
else
if(size > (1000L * 1024L))
sprintf(buffer,"(%3luM)", size / (1000L * 1024L));
else
if(size > (9L * 1024L))
sprintf(buffer,"(%3luK)", size / (1024L));
else
sprintf(buffer,"(%4lu)", size);
return(buffer);
}
#ifdef __STDC__
void fast_fetch_message_info(Mailbox *mailbox, Lview *lview)
#else
void fast_fetch_message_info(mailbox,lview)
Mailbox *mailbox;
Lview *lview;
#endif
{
Arg args[ARGLISTSIZE];
int n = 0;
MainWindow *mwin = find_main_window(mailbox);
unsigned long prefetch;
unsigned long start;
unsigned long x;
Message *message;
Message_List *message_list;
Message_List *prev = NULL;
double percentage = 0.0;
int int_percent = 0;
int old_percent = 0;
char log[FILEBUFFLEN];
Boolean fetchnomore = FALSE;
MESSAGECACHE *elt;
unsigned long len;
if(XtIsRealized(mwin->shell)) {
de_iconify(mwin->shell);
XmUpdateDisplay(mwin->shell);
}
if(mailbox->nmsgs == 0 || lview->count == 0) {
mailbox->fetched = TRUE;
mailbox->bg_timer = (XtIntervalId) 0;
return;
}
if(mailbox->type == MAILBOX_TYPE_NEWS)
prefetch = (unsigned long) preferences.news_prefetch;
else
prefetch = (unsigned long) preferences.mail_prefetch;
if(prefetch == 0L)
start = 1L;
else {
if(lview->count < prefetch)
start = 1L;
else {
start = lview->count - prefetch;
if(start < 1L)
start = 1L;
sprintf(log,MLGetLocalized(XtNmsgBackgrounding,MsgBackgrounding),start);
mm_log(log,MLNOTIFY);
}
}
mailbox->first_fetch = start;
/* Create the message list and populate with message structures. */
for(x = 1; x <= lview->count; x ++ ) {
message_list = new_message_list();
if(prev) {
prev->next = message_list;
message_list->prev = prev;
}
else
lview->message_list = message_list;
message_list->number = x;
message = new_message();
message_list->message = message;
message->msgno = x;
message->mailbox = mailbox;
message->mailstream = mailbox->mailstream;
prev = message_list;
}
/* Now fetch the messages. */
if(mailbox->type == MAILBOX_TYPE_MAIL) {
message_list = lview->message_list;
for(x = 1; x <= lview->count; x ++) {
message = message_list->message;
percentage = ((double) x / (double) lview->count) * 100.0 ;
int_percent = (int) percentage;
if((int_percent > 0)
&& (int_percent <= 100)
&& (int_percent != old_percent)) {
XtVaSetValues(mwin->slider, XmNvalue, int_percent, NULL);
XmUpdateDisplay(mwin->shell);
old_percent = int_percent;
}
if(x >= start) {
message->envelope = mail_fetchstructure(message->mailstream,
message->msgno,
&message->body);
if(message->envelope == NULL)
continue;
message->longcache = mail_lelt(message->mailstream, message->msgno);
message->fetched = TRUE;
if(message->envelope->in_reply_to != NULL)
message->references = cpystr(message->envelope->in_reply_to);
else
message->references = cpystr(EMPTYSTR);
fix_references_field(&message->references);
if(message->envelope->message_id != NULL)
message->message_id = cpystr(message->envelope->message_id);
else
message->message_id = cpystr(EMPTYSTR);
}
message->viewline = make_view_line(message);
if(message_list->next)
message_list = message_list->next;
}
}
else {
/* news. Go backwards until we find a deleted entry */
message_list = prev; /* already set to the end for us */
for(x = lview->count; x >= 1; x --) {
message = message_list->message;
percentage =
((double) (lview->count - x) / (double) lview->count) * 100.0 ;
int_percent = (int) percentage;
if((int_percent > 0)
&& (int_percent <= 100)
&& (int_percent != old_percent)) {
XtVaSetValues(mwin->slider, XmNvalue, int_percent, NULL);
XmUpdateDisplay(mwin->shell);
old_percent = int_percent;
}
if((x >= start) && (fetchnomore == FALSE)) {
message->envelope = mail_fetchstructure(message->mailstream,
message->msgno,
&message->body);
if(message->envelope == NULL)
continue;
message->longcache = mail_lelt(message->mailstream, message->msgno);
message->fetched = TRUE;
elt = &(message->longcache->elt);
if(elt->deleted) {
fetchnomore = TRUE;
if(message->msgno > 1)
mailbox->first_fetch = start = 1L;
}
if(message->envelope->in_reply_to != NULL)
message->references = cpystr(message->envelope->in_reply_to);
else
message->references = cpystr(EMPTYSTR);
fix_references_field(&message->references);
if(message->envelope->message_id != NULL)
message->message_id = cpystr(message->envelope->message_id);
else
message->message_id = cpystr(EMPTYSTR);
}
message->viewline = make_view_line(message);
if(fetchnomore == TRUE) {
lview->pruned = x;
lview->count = lview->count - lview->pruned;
lview->prune_happened = TRUE;
prev = message_list->next;
message_list->next = NULL;
free_message_list(lview->message_list,TRUE,TRUE);
lview->message_list = prev;
mm_log(MLGetLocalized(XtNmsgPruning,MsgPruning), NIL);
break;
}
if(message_list->prev)
message_list = message_list->prev;
}
}
/* make sure we get that last little bit in the scrollbar */
XtVaSetValues(mwin->slider, XmNvalue, 100, NULL);
XmUpdateDisplay(mwin->shell);
mailbox->fetched = TRUE;
if((start != 1L) && (fetchnomore == FALSE)) {
mailbox->bg_timer = XtAppAddTimeOut(context,
(mailbox->type == MAILBOX_TYPE_NEWS)
? (preferences.news_background * 1000)
: (preferences.mail_background * 1000),
(XtTimerCallbackProc) background_fetch,
mailbox);
if(mailbox->type == MAILBOX_TYPE_MAIL)
mail_parameters(mailbox->mailstream,
SET_LOOKAHEAD,
(void *) preferences.mail_fetch);
}
else
mailbox->bg_timer = (XtIntervalId) 0;
if(XtIsRealized(mwin->shell)) {
de_iconify(mwin->shell);
XmUpdateDisplay(mwin->shell);
}
return;
}
#ifdef __STDC__
void get_new_message_info(Mailbox *mailbox)
#else
void get_new_message_info(mailbox)
Mailbox *mailbox;
#endif
{
FILE *fp;
MainWindow *mwin;
MESSAGECACHE *elt;
int n = 0;
char *ptr;
Lview *lview;
Message *message;
Message_List *message_list;
Message_List *prev = NULL;
Message_List *new;
char *fixedname;
char buffer[FILEBUFFLEN];
unsigned long len;
mwin = find_main_window(mailbox);
lview = get_all_lview(mailbox->mailstream);
if(mwin == NULL || mailbox->nmsgs == 0 || lview == NULL)
return;
if(lview->message_list) {
for(prev = lview->message_list; prev->next; prev = prev->next)
;
}
for(n = lview->pruned + lview->count + 1; n <= mailbox->nmsgs; n ++) {
message_list = new_message_list();
if(prev == NULL)
lview->message_list = message_list;
else
prev->next = message_list;
message_list->prev = prev;
message_list->number = n;
message = new_message();
message_list->message = message;
message->msgno = n;
message->mailbox = mailbox;
message->mailstream = mailbox->mailstream;
message->envelope = mail_fetchstructure(message->mailstream,
message->msgno,
&message->body);
message->longcache = mail_lelt(message->mailstream, message->msgno);
if(message->envelope->in_reply_to != NULL)
message->references = cpystr(message->envelope->in_reply_to);
else
message->references = cpystr(EMPTYSTR);
fix_references_field(&message->references);
if(message->envelope->message_id != NULL)
message->message_id = cpystr(message->envelope->message_id);
else
message->message_id = cpystr(EMPTYSTR);
message->viewline = make_view_line(message);
message->fetched = TRUE;
prev = message_list;
if((preferences.newMailProg != NULL)
&& (*preferences.newMailProg != NUL_TERM)) {
sprintf(MLSender,"MLSENDER=%s",
(message->sender) ? message->sender : EMPTYSTR);
for(ptr = MLSender; *ptr; ptr ++)
if((*ptr == SPACECHAR) || (*ptr == TABCHAR) || (*ptr == DQUOTECHAR))
*ptr = '_';
putenv(MLSender);
fixedname = unfix_mailboxpath(message->mailbox->mailboxname);
sprintf(MLMailbox,"MLMAILBOX=%s%s%s",
(message->mailbox->host) ? message->mailbox->host : EMPTYSTR,
(message->mailbox->host) ? ":" : EMPTYSTR,
fixedname);
fs_give((void **) &fixedname);
for(ptr = MLMailbox; *ptr; ptr ++)
if((*ptr == SPACECHAR) || (*ptr == TABCHAR) || (*ptr == DQUOTECHAR))
*ptr = '_';
putenv(MLMailbox);
fp = popen(preferences.newMailProg,"w");
pclose(fp);
}
sprintf(buffer,MLGetLocalized(XtNmsgNewMessageFrom,MsgNewMessageFrom),
mailbox->imapname,
(message->sender) ? message->sender : EMPTYSTR,
(message->subject) ? message->subject : EMPTYSTR);
mm_log(buffer, (preferences.alert_new) ? MLNOTIFY : NIL);
}
new = sort_message_list(lview->message_list, lview->representation);
lview->message_list = new;
lview->count = mailbox->nmsgs - lview->pruned;
if((has_new_messages(lview,FALSE)) == TRUE)
lview->has_new = TRUE;
else
lview->has_new = FALSE;
if(mwin->current == lview)
view_context_switch(mwin,lview,lview);
update_logical_views(mailbox,FALSE);
return;
}
#ifdef __STDC__
void fix_references_field(char **s)
#else
void fix_references_field(s)
char **s;
#endif
{
char *start;
char *end;
char *ret;
if(*s == NULL) {
*s = cpystr(EMPTYSTR);
return;
}
if(((start = strchr(*s,'<')) != NULL)
&& ((end = strchr(start,'>')) != NULL)){
*(end + 1) = NUL_TERM;
ret = cpystr(start);
}
else
ret = cpystr(EMPTYSTR);
free(*s);
*s = ret;
return;
}
#ifdef __STDC__
Boolean background_fetch_message(Mailbox *mailbox, unsigned long msgno,
Boolean recurse)
#else
Boolean background_fetch_message(mailbox,msgno, recurse)
Mailbox *mailbox;
unsigned long msgno;
Boolean recurse;
#endif
{
Message *message;
MESSAGECACHE *elt;
int i;
unsigned long len;
message = get_message_from_mailbox(mailbox,msgno);
if((message == NULL) || (message->fetched == TRUE))
return(FALSE);
message->envelope = mail_fetchstructure(message->mailstream,
message->msgno,
&message->body);
message->longcache = mail_lelt(message->mailstream, message->msgno);
message->fetched = TRUE;
if(message->envelope->in_reply_to != NULL)
message->references = cpystr(message->envelope->in_reply_to);
else
message->references = cpystr(EMPTYSTR);
fix_references_field(&message->references);
if(message->envelope->message_id != NULL)
message->message_id = cpystr(message->envelope->message_id);
else
message->message_id = cpystr(EMPTYSTR);
update_view_line(mailbox,message);
if((mailbox->type == MAILBOX_TYPE_NEWS) && (recurse == FALSE)) {
elt = &(message->longcache->elt);
if(elt->deleted) {
/* get the rest of this fetch sequence */
for(i = message->msgno + 1;
((background_fetch_message(mailbox,i, TRUE)) == TRUE); i ++)
;
prune_mailbox(mailbox,message->msgno);
return(FALSE);
}
}
return(TRUE);
}
#ifdef __STDC__
void prune_mailbox(Mailbox *mailbox, unsigned long msgno)
#else
void prune_mailbox(mailbox,msgno)
Mailbox *mailbox;
unsigned long msgno;
#endif
{
Lview *lview;
Message_List *message_list;
Message_List *next = NULL;
Message_List *deleted;
MESSAGECACHE *elt;
Message_List *new;
unsigned long n = 0L;
lview = get_all_lview(mailbox->mailstream);
if(lview) {
new = sort_message_list(lview->message_list, REP_ASCENDING);
for(message_list = new;
(message_list
&& message_list->message
&& message_list->message->msgno != msgno);
message_list = message_list->next)
;
deleted = message_list;
for(message_list = message_list;
message_list; message_list = message_list->next) {
if(message_list->message && message_list->message->longcache) {
elt = &(message_list->message->longcache->elt);
if(elt && elt->deleted)
deleted = message_list;
else
break;
}
}
if(deleted && deleted->message) {
next = deleted->next;
deleted->next = NULL;
free_message_list(new ,TRUE, TRUE);
lview->message_list = next;
lview->pruned = deleted->message->msgno;
lview->count = lview->count - lview->pruned;
mailbox->first_fetch = 1L;
}
lview->message_list = sort_message_list(lview->message_list,
lview->representation);
}
mm_log(MLGetLocalized(XtNmsgPruning,MsgPruning), NIL);
return;
}
/* Called from the mm_flags() callback */
#ifdef __STDC__
void update_view_line_stream_msgno(MAILSTREAM *mailstream, unsigned long msgno)
#else
void update_view_line_stream_msgno(mailstream,msgno)
MAILSTREAM *mailstream;
unsigned long msgno;
#endif
{
Message *message;
Mailbox *mailbox;
mailbox = find_mailbox_from_mailstream(mailstream);
if(mailbox && mailbox->fetched) {
message = get_message_from_mailbox(mailbox,msgno);
mailbox->flags_changed ++;
if(message)
update_view_line(mailbox,message);
}
return;
}
#ifdef __STDC__
void update_view_line(Mailbox *mailbox, Message *message)
#else
void update_view_line(mailbox,message)
Mailbox *mailbox;
Message *message;
#endif
{
MainWindow *mwin;
Message_List *message_list;
XmString xstr = NULL;
Boolean different = FALSE;
mwin = find_main_window(mailbox);
if(mwin == NULL)
return;
xstr = make_view_line(message);
if(xstr == NULL)
return;
/* we only need to update things if the string has actually changed. */
if((message->viewline != NULL)
&& ((XmStringCompare(xstr,message->viewline)) == FALSE))
different = TRUE;
if(message->viewline == NULL) /* just in case wasn't set already */
different = TRUE;
if(different == TRUE) { /* Set the new structure value */
if(message->viewline)
XmStringFree(message->viewline);
message->viewline = xstr;
}
else { /* No changes needed. Go home. */
XmStringFree(xstr);
return;
}
/*
* If the current view contains the message, update it.
* Preserve highlight. If not in the view, we've already changed
* the structure value, and it will take effect on the next
* context switch. One of the reasons for checking "sameness" above
* is that highlighting gets messed up if we re-highlight the same
* string value, which toggles it off and doesn't tell us.
*/
if((mwin->current != NULL)
&& (mwin->current->mailstream == message->mailstream)) {
for(message_list = mwin->current->message_list;
message_list; message_list = message_list->next) {
if(message_list->message == message) {
mailbox->refresh_needed ++;
break;
}
}
}
mailbox->update_needed ++;
session->update_needed ++;
return;
}
#ifdef __STDC__
Message *get_message_from_mailbox(Mailbox *mailbox, unsigned long msgno)
#else
Message *get_message_from_mailbox(mailbox,msgno)
Mailbox *mailbox;
unsigned long msgno;
#endif
{
Lview *lview;
Message_List *message_list;
lview = get_all_lview(mailbox->mailstream);
if(lview) {
for(message_list = lview->message_list;
message_list; message_list = message_list->next)
if((message_list->message) && (message_list->message->msgno == msgno))
return(message_list->message);
}
return(NULL);
}
/*
* Looks at the current highlighted messages and generates an IMAP
* sequence string. This can be individual messages "n,nn,nnn,[etc.]"
* and/or message ranges denoted by "start_n:end_n". The range notation
* cuts down considerable network bandwidth, but won't work well, (if at all)
* if we have an alternate representation, like reverse order or sorted views.
* We don't even try to optimize those. Hopefully the c-client won't crash
* if we feed it an entire selected mailbox in reverse order.
*/
#ifdef __STDC__
char *generate_sequence(Lview *lview)
#else
char *generate_sequence(lview)
Lview *lview;
#endif
{
Message_List *message_list;
char *buffer;
char *sequence;
unsigned long found = 0L;
unsigned long range_begin = 0L;
unsigned long last_range = 0L;
Boolean range = FALSE;
if(lview == NULL || lview->num_selected == 0L)
return(NULL);
/*
* Overkill (worst case) allocation. 9 million messages out of
* sequence starting at 1000000 (plus a separator char) is unlikely.
* The program will have crashed elsewhere or would have hit system
* limits if somebody ever overflows this buffer.
*/
buffer = (char *) fs_get(8 * lview->num_selected);
sequence = buffer;
*sequence = NUL_TERM;
for(message_list = lview->message_list; message_list;
message_list = message_list->next) {
if(message_list->selected == FALSE)
continue;
/*
* if we're in a range sequence and haven't reached the end of it,
* update the last_range variable and keep going
*/
if((found != 0)
&& (range == TRUE)
&& (message_list->next != NULL)
&& (message_list->next->selected == TRUE)
&& (message_list->message)
&& (message_list->next->message)
&& (message_list->next->message->msgno == (last_range +1))) {
last_range = message_list->next->message->msgno;
found ++;
continue;
}
/*
* See if this qualifies as a range sequence.
*/
if((range == FALSE)
&& (message_list->next != NULL)
&& (message_list->next->selected == TRUE)
&& (message_list->message)
&& (message_list->next->message)
&& (message_list->next->message->msgno
== (message_list->message->msgno + 1))) {
range = TRUE;
range_begin = message_list->message->msgno;
last_range = message_list->next->message->msgno;
if(found != 0) {
strcat(sequence,",");
sequence += 1;
}
sprintf(sequence,"%ld", message_list->message->msgno);
sequence += strlen(sequence);
found ++;
continue;
}
/* We've found the last in a range. Flush it. */
if((range == TRUE)
&& (range_begin != 0)) {
sprintf(sequence,":%lu",last_range);
range = FALSE;
range_begin = 0L;
last_range = 0L;
found ++;
sequence += strlen(sequence);
continue;
}
/*
* Not a range. If the first message, start the string.
* Otherwise, add a comma, then the current number.
*/
if(found == 0)
sprintf(sequence,"%ld", message_list->message->msgno);
else
sprintf(sequence,",%ld", message_list->message->msgno);
found ++;
sequence += strlen(sequence);
}
return(buffer);
}
/*
* This is the same as the above function except that it builds the list
* from the current lview, ignoring highlight state. Every message in the
* lview becomes part of the sequence.
*/
#ifdef __STDC__
char *generate_sequence_unselected(Lview *lview)
#else
char *generate_sequence_unselected(lview)
Lview *lview;
#endif
{
Message_List *message_list;
char *buffer;
char *sequence;
unsigned long found = 0L;
unsigned long range_begin = 0L;
unsigned long last_range = 0L;
Boolean range = FALSE;
if(lview == NULL || lview->count == 0L)
return(NULL);
/*
* Overkill (worst case) allocation. 9 million messages out of
* sequence starting at 1000000 (plus a separator char) is unlikely.
* The program will have crashed elsewhere or would have hit system
* limits if somebody ever overflows this buffer.
*/
buffer = (char *) fs_get(8 * lview->count);
sequence = buffer;
*sequence = NUL_TERM;
for(message_list = lview->message_list; message_list;
message_list = message_list->next) {
/*
* if we're in a range sequence and haven't reached the end of it,
* update the last_range variable and keep going
*/
if((found != 0)
&& (range == TRUE)
&& (message_list->next != NULL)
&& (message_list->message)
&& (message_list->next->message)
&& (message_list->next->message->msgno == (last_range +1))) {
last_range = message_list->next->message->msgno;
found ++;
continue;
}
/*
* See if this qualifies as a range sequence.
*/
if((range == FALSE)
&& (message_list->next != NULL)
&& (message_list->message)
&& (message_list->next->message)
&& (message_list->next->message->msgno
== (message_list->message->msgno + 1))) {
range = TRUE;
range_begin = message_list->message->msgno;
last_range = message_list->next->message->msgno;
if(found != 0) {
strcat(sequence,",");
sequence += 1;
}
sprintf(sequence,"%ld", message_list->message->msgno);
sequence += strlen(sequence);
found ++;
continue;
}
/* We've found the last in a range. Flush it. */
if((range == TRUE)
&& (range_begin != 0)) {
sprintf(sequence,":%lu",last_range);
range = FALSE;
range_begin = 0L;
last_range = 0L;
found ++;
sequence += strlen(sequence);
continue;
}
/*
* Not a range. If the first message, start the string.
* Otherwise, add a comma, then the current number.
*/
if(found == 0)
sprintf(sequence,"%ld", message_list->message->msgno);
else
sprintf(sequence,",%ld", message_list->message->msgno);
found ++;
sequence += strlen(sequence);
}
return(buffer);
}
/*
* A partial misnomer. The "asking" is done during the file select.
* The routine just saves a binary buffer or returns.
*/
#ifdef __STDC__
void ask_save(Widget w, Binary_Buffer *binary_buffer)
#else
void ask_save(w,binary_buffer)
Widget w;
Binary_Buffer *binary_buffer;
#endif
{
FILE *fp;
Boolean append_it;
char *filename;
int errors = 0;
filename = file_select(w, NULL, NULL, NULL, TRUE, &append_it);
if(filename == NULL)
return;
push_cursor(WATCH_CURSOR);
if((fp = fopen(filename,(append_it == TRUE) ? "a" : "w")) == NULL)
errors ++;
if(! errors) {
if(fwrite(binary_buffer->data,binary_buffer->length,1,fp) != 1)
errors ++;
if(fclose(fp))
errors ++;
}
if(errors)
mm_log(MLGetLocalized(XtNmsgSaveFail,MsgSaveFail), WARN);
else
mm_log(MLGetLocalized(XtNmsgSaveSuccess,MsgSaveSuccess), NIL);
fs_give((void **) &filename);
pop_cursor();
return;
}
#ifdef __STDC__
int copy_message_to_mailbox(MAILSTREAM *mailstream, unsigned long msgno,
char *dest)
#else
int copy_message_to_mailbox(mailstream,msgno,dest)
MAILSTREAM *mailstream;
unsigned long msgno;
char *dest;
#endif
{
extern STRINGDRIVER mail_string;
STRING bs;
int result = SYSCALL_SUCCESS;
char *data1 = NULL;
char *data2 = NULL;
char *everything = NULL;
if((mailstream == NULL) || (msgno == 0L)
|| (dest == NULL) || (*dest == NUL_TERM))
return(SYSCALL_FAILURE);
data1 = cpystr(mail_fetchheader(mailstream,msgno));
data2 = cpystr(mail_fetchtext(mailstream,msgno));
if((data1 == NULL) && (data2 == NULL))
return(SYSCALL_FAILURE);
everything = (char *) fs_get(strlen(data1) + strlen(data2) + 1);
strcpy(everything,data1);
strcat(everything,data2);
fs_give((void **) &data1);
fs_give((void **) &data2);
INIT(&bs, mail_string,everything,strlen(everything));
if((mail_append_full(NIL,dest,NIL,NIL, &bs)) == NIL)
result = SYSCALL_FAILURE;
fs_give((void **) &everything);
return(result);
}
#ifdef __STDC__
int copy_message_to_cachemailbox(MAILSTREAM *mailstream, unsigned long msgno,
char *dest)
#else
int copy_message_to_cachemailbox(mailstream,msgno,dest)
MAILSTREAM *mailstream;
unsigned long msgno;
char *dest;
#endif
{
extern STRINGDRIVER mail_string;
STRING bs;
int result = SYSCALL_SUCCESS;
char *data1 = NULL;
char *data2 = NULL;
char *everything = NULL;
if((mailstream == NULL) || (msgno == 0L)
|| (dest == NULL) || (*dest == NUL_TERM))
return(SYSCALL_FAILURE);
data1 = cpystr(mail_fetchheader(mailstream,msgno));
data2 = cpystr(mail_fetchtext(mailstream,msgno));
if((data1 == NULL) && (data2 == NULL))
return(SYSCALL_FAILURE);
everything = (char *) fs_get(strlen(data1) + strlen(data2) + 1);
strcpy(everything,data1);
strcat(everything,data2);
fs_give((void **) &data1);
fs_give((void **) &data2);
INIT(&bs, mail_string,everything,strlen(everything));
if((bezerk_cache_append(NIL,dest,NIL,NIL, &bs)) == NIL)
result = SYSCALL_FAILURE;
fs_give((void **) &everything);
return(result);
}
syntax highlighted by Code2HTML, v. 0.9.1