/* 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 = ""; } } 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); }