/* mlcompose.c */ #include "ml.h" char compose_address_translations[] = "Tab: complete-address()\n"; Menu compose_file_menu[] = { { NULL, "load_draft", NUL_TERM, compose_load_draft, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "save_draft", NUL_TERM, compose_save_draft, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "print", NUL_TERM, compose_print, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "insert_file", NUL_TERM, compose_insert_file, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "address_book", NUL_TERM, main_address_book, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "note_book", NUL_TERM, main_note_book, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "close_window", NUL_TERM, compose_destroy_current, NULL, 0, NULL, NULL, BTN_ON }, }; Menu compose_attach_menu[] = { { NULL, "attach_file", NUL_TERM, compose_attach_file, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "attach_multi", NUL_TERM, compose_attach_multi, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "createattach", NUL_TERM, compose_createattach, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "delete_part", NUL_TERM, compose_delete_part, NULL, 0, NULL, NULL, BTN_NOATTACH|BTN_NOATTACHSELECT }, }; Menu compose_edit_menu[] = { { NULL, "cut_text", NUL_TERM, compose_cut, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "copy_text", NUL_TERM, compose_copy, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "paste_text", NUL_TERM, compose_paste, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "spell", NUL_TERM, compose_spell, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "attach_menu", NUL_TERM, NULL, compose_attach_menu, XtNumber(compose_attach_menu), NULL, NULL, BTN_ON }, }; Menu compose_option_menu[] = { { NULL, "configure", NUL_TERM, compose_options, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "parameters", NUL_TERM, compose_parameters, NULL, 0, NULL, NULL, BTN_ON }, }; Menu compose_send_menu[] = { { NULL, "send_message", NUL_TERM, send_message, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "send_autograph", BTN_ON, compose_send_autograph, NULL, 0, NULL, NULL, BTN_ON }, }; Menu compose_menu[] = { { NULL, "file_menu", NUL_TERM, NULL, compose_file_menu, XtNumber(compose_file_menu), NULL, NULL, BTN_ON }, { NULL, "edit_menu", NUL_TERM, NULL, compose_edit_menu, XtNumber(compose_edit_menu), NULL, NULL, BTN_ON }, { NULL, "option_menu", NUL_TERM, NULL, compose_option_menu, XtNumber(compose_option_menu), NULL, NULL, BTN_ON }, { NULL, "send_menu", NUL_TERM, NULL, compose_send_menu, XtNumber(compose_send_menu), NULL, NULL, BTN_ON }, { NULL, "HELP", NUL_TERM, compose_help, NULL, 0, NULL, NULL, BTN_ON }, }; Button_Menu compose_secondbuttons[] = { { "compose_insert_file_btn", compose_insert_file, NULL, BTN_ON, NULL }, { "compose_attach_file_btn", compose_attach_file, NULL, BTN_ON, NULL }, { "compose_reply_insert_btn", compose_reply_insert, NULL, BTN_ON, NULL }, { "compose_send_message_btn", send_message, NULL, BTN_ON, NULL }, { "compose_cancel_btn", compose_destroy_current, NULL, BTN_ON, NULL }, }; #ifdef __STDC__ void compose_check_buttons(MLCompose *compose) #else void compose_check_buttons(compose) MLCompose *compose; #endif { if(compose && compose->window) update_buttons(compose->window->buttonlist, compose->window->buttonstate); return; } #ifdef __STDC__ void free_MLCompose(MLCompose *compose) #else void free_MLCompose(compose) MLCompose *compose; #endif { if(compose != NULL) { free_buttonlist(compose->window->buttonlist); fs_give((void **) &compose->window); free_MLComposeOptions(compose->options); compose->options = NULL; if(compose->in_reply_to != NULL) fs_give((void **) &compose->in_reply_to); if(compose->reply_text != NULL) fs_give((void **) &compose->reply_text); if(compose->remail_header != NULL) fs_give((void **) &compose->remail_header); fs_give((void **) &compose); } return; } #ifdef __STDC__ void free_MLComposeOptions(MLComposeOptions *options) #else void free_MLComposeOptions(options) MLComposeOptions *options; #endif { if(options) { if(options->window) { if(options->window->buttonlist) fs_give((void **) &options->window->buttonlist); fs_give((void **) &options->window); } if(options->mailhost) fs_give((void **) &options->mailhost); if(options->nntphost) fs_give((void **) &options->nntphost); if(options->domain) fs_give((void **) &options->domain); if(options->replyto) fs_give((void **) &options->replyto); if(options->charset) fs_give((void **) &options->charset); if(options->sigfile) fs_give((void **) &options->sigfile); if(options->language) fs_give((void **) &options->language); if(options->outlog) fs_give((void **) &options->outlog); if(options->defcc) fs_give((void **) &options->defcc); if(options->defbcc) fs_give((void **) &options->defbcc); if(options->prefix) fs_give((void **) &options->prefix); fs_give((void **) &options); } return; } #ifdef __STDC__ MLComposeWindow *new_MLComposeWindow(void) #else MLComposeWindow *new_MLComposeWindow() #endif { MLComposeWindow *composewindow = (MLComposeWindow *) fs_get(sizeof(MLComposeWindow)); composewindow->buttonlist = NULL; composewindow->attach_list_selection = 0; composewindow->toggled_newsgroups = FALSE; composewindow->toggled_bcc = FALSE; return(composewindow); } #ifdef __STDC__ MLComposeOptions *new_MLComposeOptions(void) #else MLComposeOptions *new_MLComposeOptions() #endif { MLComposeOptions *options = (MLComposeOptions *) fs_get(sizeof(MLComposeOptions)); options->window = NULL; options->verbose = preferences.smtp_debug; options->keep_open = preferences.keep_open; options->send_eight = preferences.send_eight; options->word_wrap = preferences.word_wrap; options->message_log = preferences.logit; options->log_attachments = preferences.log_full; options->verbose_tmp = preferences.smtp_debug; options->keep_open_tmp = preferences.keep_open; options->send_eight_tmp = preferences.send_eight; options->word_wrap_tmp = preferences.word_wrap; options->message_log_tmp = preferences.logit; options->log_attachments_tmp = preferences.log_full; options->mailhost = cpystr(preferences.smtp_server); options->nntphost = cpystr(preferences.nntp_server); options->domain = cpystr(preferences.default_domain); options->replyto = cpystr(preferences.reply_address); options->charset = cpystr(preferences.charset); options->sigfile = cpystr(preferences.signature_file); options->language = cpystr(preferences.language); options->outlog = cpystr(preferences.sendlog); options->defcc = cpystr(preferences.default_cc); options->defbcc = cpystr(preferences.default_bcc); options->prefix = cpystr(preferences.reply_prefix); return(options); } #ifdef __STDC__ MLCompose *new_MLCompose(void) #else MLCompose *new_MLCompose() #endif { MLCompose *mlcompose = (MLCompose *) fs_get(sizeof(MLCompose)); mlcompose->window = new_MLComposeWindow(); mlcompose->options = new_MLComposeOptions(); mlcompose->spellwindow = NULL; mlcompose->compose_type = COMPOSE_NEW; mlcompose->message = NULL; mlcompose->in_reply_to = NULL; mlcompose->reply_text = NULL; mlcompose->remail_header = NULL; mlcompose->in_ispell = FALSE; mlcompose->has_newsgroups = FALSE; mlcompose->parameters = NULL; mlcompose->attachments = NULL; mlcompose->part_list = NULL; mlcompose->next = NULL; mlcompose->prev = NULL; return(mlcompose); } #ifdef __STDC__ void compose_message(Compose_Type type, Boolean news, Lview *lview, Message *message, Read_Info *read_info) #else void compose_message(type, news, lview, message, read_info) Compose_Type type; Boolean news; Lview *lview; Message *message; Read_Info *read_info; #endif { MLCompose *compose = new_MLCompose(); /* Create Window */ create_compose_window(compose, type, news); /* Link to session */ if(session->compose) { compose->next = session->compose; session->compose->prev = compose; } session->compose = compose; /* Set initial options. */ /* Get|Set known message values. */ if(read_info != NULL) load_compose_from_read(compose, type, news, read_info); else load_compose_info(compose, type, news, lview, message); if(compose->attachments == NULL) { compose->window->buttonstate |= BTN_NOATTACH; compose->window->buttonstate |= BTN_NOATTACHSELECT; } else make_attachment_list(compose, TRUE); compose_set_window_title(compose,type,news,lview,message,read_info); compose_check_buttons(compose); return; } #ifdef __STDC__ void create_compose_window(MLCompose *compose, Compose_Type type, Boolean news) #else void create_compose_window(compose, type, news) MLCompose *compose; Compose_Type type; Boolean news; #endif { Arg args[ARGLISTSIZE]; int n = 0; XtTranslations translations; XtSetArg (args[n], XmNdeleteResponse, XmDO_NOTHING); n++; compose->window->shell = XtCreatePopupShell("compose", topLevelShellWidgetClass, session->shell, NULL, 0); AddDestroyCallback (compose->window->shell); setup_editres(compose->window->shell); if(compose_icon != (Pixmap) None) XtVaSetValues(compose->window->shell, XmNiconPixmap,compose_icon, NULL); compose->window->form = XmCreateForm(compose->window->shell,"form", args, n); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n ++; compose->window->menubar = XmCreateMenuBar(compose->window->form,"menubar", args, n); n = 0; XtManageChild(compose->window->menubar); make_buttons(&compose->window->buttonlist, NULL, compose->window->menubar, compose_menu, XtNumber(compose_menu), BTN_ON, (XtPointer) compose, ROOTMENULEVEL); XtSetArg(args[n], XmNadjustMargin, FALSE); n ++; XtSetArg(args[n], XmNmarginWidth, 0); n ++; XtSetArg(args[n], XmNborderWidth, 0); n ++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNtopWidget, compose->window->menubar); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n ++; XtSetArg(args[n], XmNpacking, XmPACK_COLUMN); n ++; compose->window->rowcol = XmCreateRowColumn(compose->window->form, "rowcol", args, n); n = 0; XtManageChild(compose->window->rowcol); make_secondbuttons(compose->window->buttonlist, compose->window->rowcol, compose_secondbuttons, XtNumber(compose_secondbuttons), BTN_ON, (XtPointer) compose); XtSetArg(args[n], XmNtraversalOn, FALSE); n ++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNtopWidget, compose->window->rowcol); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNborderWidth, 0); n ++; compose->window->to_button = XmCreatePushButton(compose->window->form,"to_button", args, n); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNtopWidget, compose->window->rowcol); n ++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNleftWidget,compose->window->to_button); n ++; compose->window->to_text = XmCreateTextField(compose->window->form, "to_textfld", args, n); n = 0; XtSetArg(args[n], XmNtraversalOn, FALSE); n ++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNtopWidget, compose->window->rowcol); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNborderWidth, 0); n ++; compose->window->newsgroups_button = XmCreatePushButton(compose->window->form,"newsgroups_button", args, n); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNtopWidget, compose->window->rowcol); n ++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNleftWidget,compose->window->newsgroups_button); n ++; compose->window->newsgroups_text = XmCreateTextField(compose->window->form,"newsgroups_textfld", args, n); n = 0; translations = XtParseTranslationTable(GLOBAL_text_field_translations); XtOverrideTranslations(compose->window->to_text,translations); translations = XtParseTranslationTable(GLOBAL_nonterminal_text_field_translations); XtOverrideTranslations(compose->window->to_text,translations); translations = XtParseTranslationTable(compose_address_translations); XtOverrideTranslations(compose->window->to_text,translations); XtAddCallback(compose->window->to_text, XmNmodifyVerifyCallback, (XtCallbackProc) text_field_edit, NULL); translations = XtParseTranslationTable(GLOBAL_text_field_translations); XtOverrideTranslations(compose->window->newsgroups_text,translations); translations = XtParseTranslationTable(GLOBAL_nonterminal_text_field_translations); XtOverrideTranslations(compose->window->newsgroups_text,translations); translations = XtParseTranslationTable(compose_address_translations); XtOverrideTranslations(compose->window->newsgroups_text,translations); XtAddCallback(compose->window->newsgroups_text, XmNmodifyVerifyCallback, (XtCallbackProc) text_field_edit, NULL); XtAddCallback(compose->window->newsgroups_button, XmNactivateCallback, (XtCallbackProc) compose_toggle_news, compose ); XtAddCallback(compose->window->to_button, XmNactivateCallback, (XtCallbackProc) compose_toggle_news, compose ); if(news == TRUE) { XtManageChild(compose->window->newsgroups_button); XtManageChild(compose->window->newsgroups_text); compose->window->toggled_newsgroups = TRUE; } else { XtManageChild(compose->window->to_button); XtManageChild(compose->window->to_text); compose->window->toggled_newsgroups = FALSE; } XtSetArg(args[n], XmNtraversalOn, FALSE); n ++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNtopWidget, compose->window->to_text); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNborderWidth, 0); n ++; compose->window->subject_button = XmCreatePushButton(compose->window->form,"subject_button", args, n); n = 0; XtManageChild(compose->window->subject_button); XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNtopWidget, compose->window->to_text); n ++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNleftWidget,compose->window->subject_button); n ++; compose->window->subject_text = XmCreateTextField(compose->window->form, "subject_textfld", args, n); n = 0; XtManageChild(compose->window->subject_text); translations = XtParseTranslationTable(GLOBAL_text_field_translations); XtOverrideTranslations(compose->window->subject_text,translations); translations = XtParseTranslationTable(GLOBAL_nonterminal_text_field_translations); XtOverrideTranslations(compose->window->subject_text,translations); XtAddCallback(compose->window->subject_text, XmNmodifyVerifyCallback, (XtCallbackProc) text_field_edit, NULL); XtAddCallback(compose->window->subject_button, XmNactivateCallback, (XtCallbackProc) generate_subject, compose ); XtSetArg(args[n], XmNtraversalOn, FALSE); n ++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNtopWidget, compose->window->subject_text); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNborderWidth, 0); n ++; compose->window->cc_button = XmCreatePushButton(compose->window->form, "cc_button", args, n); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNtopWidget, compose->window->subject_text); n ++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNleftWidget,compose->window->cc_button); n ++; compose->window->cc_text = XmCreateTextField(compose->window->form, "cc_textfld", args, n); n = 0; translations = XtParseTranslationTable(GLOBAL_text_field_translations); XtOverrideTranslations(compose->window->cc_text,translations); translations = XtParseTranslationTable(GLOBAL_nonterminal_text_field_translations); XtOverrideTranslations(compose->window->cc_text,translations); translations = XtParseTranslationTable(compose_address_translations); XtOverrideTranslations(compose->window->cc_text,translations); XtAddCallback(compose->window->cc_text, XmNmodifyVerifyCallback, (XtCallbackProc) text_field_edit, NULL); XtSetArg(args[n], XmNtraversalOn, FALSE); n ++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNtopWidget, compose->window->subject_text); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNborderWidth, 0); n ++; compose->window->bcc_button = XmCreatePushButton(compose->window->form, "bcc_button", args, n); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNtopWidget, compose->window->subject_text); n ++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNleftWidget,compose->window->bcc_button); n ++; compose->window->bcc_text = XmCreateTextField(compose->window->form, "bcc_textfld", args, n); n = 0; translations = XtParseTranslationTable(GLOBAL_text_field_translations); XtOverrideTranslations(compose->window->bcc_text,translations); translations = XtParseTranslationTable(GLOBAL_nonterminal_text_field_translations); XtOverrideTranslations(compose->window->bcc_text,translations); translations = XtParseTranslationTable(compose_address_translations); XtOverrideTranslations(compose->window->bcc_text,translations); XtAddCallback(compose->window->bcc_text, XmNmodifyVerifyCallback, (XtCallbackProc) text_field_edit, NULL); XtAddCallback(compose->window->cc_button, XmNactivateCallback, (XtCallbackProc) compose_toggle_cc, compose ); XtAddCallback(compose->window->bcc_button, XmNactivateCallback, (XtCallbackProc) compose_toggle_cc, compose ); XtManageChild(compose->window->cc_button); XtManageChild(compose->window->cc_text); compose->window->toggled_bcc = FALSE; XtSetArg(args[n], XmNtraversalOn, FALSE); n ++; XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); n ++; XtSetArg(args[n], XmNlistSizePolicy,XmCONSTANT); n ++; XtSetArg(args[n], XmNselectionPolicy,XmSINGLE_SELECT); n ++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNtopWidget, compose->window->cc_text); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n ++; compose->window->attach_list = XmCreateScrolledList(compose->window->form,"partlist",args,n); n = 0; XtManageChild(compose->window->attach_list); XtAddCallback(compose->window->attach_list, XmNsingleSelectionCallback, (XtCallbackProc) select_attach, compose); XtAddCallback(compose->window->attach_list, XmNdefaultActionCallback, (XtCallbackProc) double_click_attach, compose); XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNtopWidget, compose->window->attach_list); n ++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNeditable, TRUE); n ++; XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n ++; XtSetArg(args[n], XmNwordWrap, TRUE); n ++; XtSetArg(args[n], XmNcolumns, COMPOSEWIDTH - 1); n ++; XtSetArg(args[n], XmNscrollVertical, TRUE); n ++; XtSetArg(args[n], XmNscrollHorizontal, FALSE ); n ++; compose->window->compose_text = XmCreateScrolledText(compose->window->form, "text", args, n); n = 0; XtManageChild(compose->window->compose_text); translations = XtParseTranslationTable(GLOBAL_text_translations); XtOverrideTranslations(compose->window->compose_text, translations); translations = XtParseTranslationTable(GLOBAL_compose_pop_translations); XtOverrideTranslations(compose->window->compose_text, translations); XtAddCallback(compose->window->compose_text, XmNmodifyVerifyCallback, (XtCallbackProc) text_hex_edit, NULL); XtAddCallback(compose->window->shell, XmNdestroyCallback, (XtCallbackProc) compose_destroy, compose); XtManageChild(compose->window->form); XtManageChild(compose->window->shell); XtPopup(compose->window->shell, XtGrabNone); return; } #ifdef __STDC__ void compose_destroy_current(Widget w, MLCompose *compose, XtPointer xp) #else void compose_destroy_current(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { if(compose->in_ispell == TRUE) return; if(preferences.confirmDestroy == TRUE) if((ml_confirm(compose->window->shell, MLGetLocalized(XtNmsgDestroyEdit, MsgDestroyEdit),CONFIRM_YES_NO)) == FALSE) return; compose_close_window(w,compose,xp); return; } #ifdef __STDC__ void compose_close_window(Widget w, MLCompose *compose, XtPointer xp) #else void compose_close_window(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { if(compose->in_ispell == TRUE) return; if(compose) { XtPopdown(compose->window->shell); XtDestroyWidget(compose->window->shell); } return; } #ifdef __STDC__ void compose_destroy(Widget w, MLCompose *compose, XtPointer xp) #else void compose_destroy(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { if(compose) { if(compose->next) compose->next->prev = compose->prev; if(compose == session->compose) session->compose = compose->next; else compose->prev->next = compose->next; free_MLCompose(compose); } return; } #ifdef __STDC__ void compose_wrap_off(Widget w, MLCompose *compose, XtPointer xp) #else void compose_wrap_off(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { Arg args[ARGLISTSIZE]; int n = 0; XtTranslations translations; char *str = NULL; if((compose != NULL) && (compose->options != NULL)) { compose->options->word_wrap = FALSE; str = XmTextGetString(compose->window->compose_text); XtDestroyWidget(compose->window->compose_text); XtSetArg(args[n], XmNeditable, TRUE); n ++; XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n ++; XtSetArg(args[n], XmNwordWrap, FALSE); n ++; XtSetArg(args[n], XmNcolumns, COMPOSEWIDTH - 1); n ++; XtSetArg(args[n], XmNscrollVertical, TRUE); n ++; XtSetArg(args[n], XmNscrollHorizontal, TRUE ); n ++; compose->window->compose_text = XmCreateScrolledText(compose->window->form, "compose_text", args, n); n = 0; translations = XtParseTranslationTable(GLOBAL_text_translations); XtOverrideTranslations(compose->window->compose_text, translations); XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNtopWidget, compose->window->attach_list); n ++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n ++; XtSetValues(XtParent(compose->window->compose_text), args, n); n = 0; XtManageChild(compose->window->compose_text); XmTextSetString(compose->window->compose_text, str); fs_give((void **) &str); } return; } #ifdef __STDC__ void compose_wrap_on(Widget w, MLCompose *compose, XtPointer xp) #else void compose_wrap_on(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { Arg args[ARGLISTSIZE]; int n = 0; char *str = NULL; XtTranslations translations; if((compose != NULL) && (compose->options != NULL)) { compose->options->word_wrap = TRUE; str = XmTextGetString(compose->window->compose_text); XtDestroyWidget(compose->window->compose_text); XtSetArg(args[n], XmNeditable, TRUE); n ++; XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n ++; XtSetArg(args[n], XmNwordWrap, TRUE); n ++; XtSetArg(args[n], XmNcolumns, COMPOSEWIDTH - 1); n ++; XtSetArg(args[n], XmNscrollVertical, TRUE); n ++; XtSetArg(args[n], XmNscrollHorizontal, FALSE ); n ++; compose->window->compose_text = XmCreateScrolledText(compose->window->form,"compose_text", args, n); n = 0; translations = XtParseTranslationTable(GLOBAL_text_translations); XtOverrideTranslations(compose->window->compose_text, translations); XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNtopWidget, compose->window->attach_list); n ++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n ++; XtSetValues(XtParent(compose->window->compose_text), args, n); n = 0; XtManageChild(compose->window->compose_text); XmTextSetString(compose->window->compose_text, str); fs_give((void **) &str); XtSetArg(args[n], XmNwordWrap, TRUE); n ++; XtSetArg(args[n], XmNscrollHorizontal, FALSE ); n ++; XtSetValues(compose->window->compose_text, args, n); n = 0; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n ++; XtSetValues(XtParent(compose->window->compose_text), args, n); n = 0; } return; } #ifdef __STDC__ void compose_toggle_cc(Widget w, MLCompose *compose, XtPointer xp) #else void compose_toggle_cc(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { if(compose != NULL) { if(compose->window->toggled_bcc == TRUE) { compose->window->toggled_bcc = FALSE; XtUnmanageChild(compose->window->bcc_button); XtUnmanageChild(compose->window->bcc_text); XtManageChild(compose->window->cc_button); XtManageChild(compose->window->cc_text); } else { compose->window->toggled_bcc = TRUE; XtUnmanageChild(compose->window->cc_button); XtUnmanageChild(compose->window->cc_text); XtManageChild(compose->window->bcc_button); XtManageChild(compose->window->bcc_text); } } return; } #ifdef __STDC__ void compose_toggle_news(Widget w, MLCompose *compose, XtPointer xp) #else void compose_toggle_news(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { if(compose != NULL) { if(compose->window->toggled_newsgroups == TRUE) { compose->window->toggled_newsgroups = FALSE; XtUnmanageChild(compose->window->newsgroups_button); XtUnmanageChild(compose->window->newsgroups_text); XtManageChild(compose->window->to_button); XtManageChild(compose->window->to_text); } else { compose->window->toggled_newsgroups = TRUE; XtUnmanageChild(compose->window->to_button); XtUnmanageChild(compose->window->to_text); XtManageChild(compose->window->newsgroups_button); XtManageChild(compose->window->newsgroups_text); } } return; } #ifdef __STDC__ void compose_set_window_title(MLCompose *compose, Compose_Type type, Boolean news, Lview *lview, Message *message, Read_Info *read_info) #else void compose_set_window_title(compose, type, news, lview, message, read_info) MLCompose *compose; Compose_Type type; Boolean news; Lview *lview; Message *message; Read_Info *read_info; #endif { char *basestr = NULL; switch (type) { case COMPOSE_REPLY: basestr = MLGetLocalized(XtNmsgReplySender,MsgReplySender); break; case COMPOSE_REPLYALL: basestr = MLGetLocalized(XtNmsgReplyAll,MsgReplyAll); break; case COMPOSE_FORWARD: case COMPOSE_FORWARDATTACH: basestr = MLGetLocalized(XtNmsgForward,MsgForward); break; case COMPOSE_REMAIL: basestr = MLGetLocalized(XtNmsgRemail,MsgRemail); break; case COMPOSE_NEW: default: basestr = MLGetLocalized(XtNmsgComposeNew,MsgComposeNew); break; } XtVaSetValues(compose->window->shell, XmNtitle, basestr, NULL); return; } /* * This is a fat function, and does almost all the dirty work. When it * comes back, the message should be on its way. * * It takes a compose structure which * points to an open compose window, extracts the stuff from * the windows (which are presumably more current than the Compose_Info * structures), connects any attachments, and sends it off. It also * determines whether it is appropriate to send news, mail or both. * On success, the current session is killed; the compose window is * restored to any previous (or next) composings, or otherwise closes * the window. On failure the message is left intact so the user can * take some form of action to correct the condition, or perhaps save * the work, or whatever. */ #ifdef __STDC__ void send_message(Widget w, MLCompose *compose, XtPointer xp) #else void send_message(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { SMTPSTREAM *smtp_stream = NIL; SMTPSTREAM *nntp_stream = NIL; ENVELOPE *envelope = NULL; ENVELOPE *news_envelope = NULL; BODY *body = NULL; BODY *currbody = NULL; PART *part = NULL; char **mailhosts = NULL; char **newshosts = NULL; Boolean intl = FALSE; char *chk; unsigned long len; char *default_host = NULL; long openflags = 0L; struct mail_body_parameter *params; Boolean sendnews = FALSE; Boolean sendmail = TRUE; Boolean retry = FALSE; Boolean attach_text = FALSE; char *from = NULL; char *to = NULL; char *newsgroups = NULL; char *subject = NULL; char *cc = NULL; char *bcc = NULL; char *temp_text = NULL; char *text = NULL; char *fixed_subject = NULL; char msgno_string[32]; int errors = 0; if((CheckConnection()) == FALSE) { mm_log(MLGetLocalized(XtNmsgNotConnected,MsgNotConnected),WARN); return; } if((compose->options->domain != NULL) && (*compose->options->domain != NUL_TERM)) default_host = cpystr(compose->options->domain); else default_host = cpystr(compose->options->mailhost); push_cursor(WATCH_CURSOR); if(! default_host) default_host = cpystr(EMPTYSTR); mailhosts = (char **) fs_get( 2 * sizeof(char *)); mailhosts[0] = cpystr(compose->options->mailhost); mailhosts[1] = NULL; newshosts = (char **) fs_get( 2 * sizeof(char *)); newshosts[0] = cpystr(compose->options->nntphost); newshosts[1] = NULL; from = cpystr(compose->options->replyto); /* Collect message information from window. */ newsgroups = GetTextField(compose->window->newsgroups_text); to = GetTextField(compose->window->to_text); subject = GetTextField(compose->window->subject_text); cc = GetTextField(compose->window->cc_text); bcc = GetTextField(compose->window->bcc_text); text = XmTextGetString(compose->window->compose_text); /* See if the text has international chars we might need to encode */ for(chk = text; (*chk != NUL_TERM) ; chk ++ ) if(((unsigned char) *chk) >= (unsigned char) 0x80) intl = TRUE; /* * Do two conversions. First translate paragraphs to LF terminated * text. Then turn LF to CRLF for sending. The reason for doing this * in two steps is so we can allocate approximately the right amount * of space in each function, and not have to overkill the memory * requirements. It also compartmentalizes the functionality. * */ if(compose->options->word_wrap == TRUE) temp_text = wrap_text(text, COMPOSEWIDTH - 1); else temp_text = cpystr(text); fs_give((void **) &text); text = lftocrlf(temp_text); fs_give((void **) &temp_text); if((intl == TRUE) && (compose->options->send_eight == FALSE)) temp_text = (char *) rfc822_8bit((unsigned char *) text, (unsigned long) strlen(text), &len); else temp_text = NULL; if((newsgroups != NULL) && (*(first_nonwhite(newsgroups)) != NUL_TERM)) sendnews = TRUE; if( (*(first_nonwhite(to)) == NUL_TERM) && (*(first_nonwhite(cc)) == NUL_TERM) && (*(first_nonwhite(bcc)) == NUL_TERM)) sendmail = FALSE; /* No recipients. Make sure it fails. */ if((sendnews == FALSE) && (sendmail == FALSE)) retry = TRUE; if(compose->options->verbose == TRUE) openflags |= SOP_DEBUG; if(sendnews == TRUE) { nntp_stream = nntp_open(newshosts, openflags); if(nntp_stream == NIL) { mm_log(MLGetLocalized(XtNmsgOpenNNTPFailed,MsgOpenNNTPFailed),WARN); retry = TRUE; } } if(compose->options->send_eight == TRUE) openflags |= SOP_ESMTP; if(sendmail == TRUE) { smtp_stream = smtp_open(mailhosts, openflags); if(smtp_stream == NIL) { mm_log(MLGetLocalized(XtNmsgOpenSMTPFailed,MsgOpenSMTPFailed),WARN); retry = TRUE; } } /* * We've got our neccessary stream(s) open. Now build the message. */ body = mail_newbody(); envelope = mail_newenvelope(); /* Don't send any empty multiparts. Won't work */ fix_empty_attachments(compose); if(compose->attachments) { body->contents.part = compose->attachments; body->type = TYPEMULTIPART; body->encoding = ENC7BIT; /* * Our text portion (if there is one) * will become the first part of the multipart */ if(*text != NUL_TERM) { attach_text = TRUE; part = mail_newbody_part(); currbody = &(part->body); part->next = body->contents.part; body->contents.part = part; } else currbody = NULL; } else /* Not a multipart. Just the text message. */ currbody = body; /* * Set the parameters for CHARSET and LANGUAGE in the parent * compose structure. We only want to do this once; and this function * might be re-entered if options->keep_open is set. */ if(intl) { for(params = compose->parameters; params != NULL; params = params->next) if((params->attribute != NULL) && (strcasecmp(params->attribute,CHARSET_STR) == STRMATCH)) break; /* * NULL params means "CHARSET" wasn't found, * so initialize it (if not US-ASCII). */ if(params == NULL) { if((strcasecmp(compose->options->charset,US_ASCII_STR) != STRMATCH)) { params = mail_newbody_parameter(); params->attribute = cpystr(CHARSET_STR); params->value = cpystr(compose->options->charset); if(compose->parameters) params->next = compose->parameters; compose->parameters = params; } } } /* * Now do the same (though a bit different logic) for LANGUAGE. */ if(*compose->options->language) { for(params = compose->parameters; params != NULL; params = params->next) if((params->attribute != NULL) && (strcasecmp(params->attribute,"LANGUAGE") == STRMATCH)) break; if(params == NULL) { params = mail_newbody_parameter(); params->attribute = cpystr("LANGUAGE"); params->value = cpystr(compose->options->language); if(compose->parameters) params->next = compose->parameters; compose->parameters = params; } } /* * Attach our text to the body. * If we have 8-bit chars, we start off with 8bit encoding * for NNTP. After that's sent we'll have to check and perhaps * switch to Q-P if desired or the mailstream doesn't support it. */ if(currbody) { currbody->type = TYPETEXT; currbody->encoding = (intl == TRUE) ? ENC8BIT : ENC7BIT; currbody->contents.text = (unsigned char *) text; currbody->size.bytes = (unsigned long) strlen((char *) text); currbody->parameter = copy_params(compose->parameters, intl); } /* * Now build the appropriate envelope(s). * Warning: The c-client appears to trash the calling text strings * in rfc822_parse_addr(), which text_to_address() calls... So, don't * parse the same string twice to get a duplicate. Use copy_address() * instead. */ envelope->from = text_to_address(from,default_host); envelope->to = text_to_address(to, default_host); envelope->cc = text_to_address(cc, default_host); envelope->bcc = text_to_address(bcc, default_host); envelope->reply_to = copy_address(envelope->from); envelope->return_path = mail_newaddr(); if(envelope->from) { if(envelope->from->mailbox) envelope->return_path->mailbox = cpystr(envelope->from->mailbox); if(envelope->from->host) envelope->return_path->host = cpystr(envelope->from->host); } /* * The sender field is our real bonafide Unix name. * This is done to thwart forgeries. This address is also used * for delivery bounces. Making certain that it can be used for * this purpose is a local system administration issue. That is, * if incoming SMTP is not allowed on the system, it should be * MX forwarded to a mail hub which can process the errors. */ if(compose->compose_type == COMPOSE_REMAIL) { envelope->remail = cpystr(compose->remail_header); body->type = TYPETEXT; if(body->subtype) fs_give((void **) &body->subtype); body->subtype = NULL; body->encoding = ENC7BIT; } else { envelope->sender = mail_newaddr(); envelope->sender->mailbox = cpystr(local_auth.username); envelope->sender->host = cpystr(local_auth.hostname); } envelope->subject = cpystr(subject); if(compose->in_reply_to) envelope->in_reply_to = cpystr(compose->in_reply_to); /* * Generate a message-id and date. Note that we also supply the * real Unix credentials here as the second stage of * forgery suppression. */ envelope->message_id = (char *) fs_get(MESSAGE_ID_LENGTH); sprintf(envelope->message_id,"<%s-%s.%d.%d.%s@%s>", PROGRAM, MLVERSION, time(NULL), rand() % 10000, local_auth.username, local_auth.hostname); envelope->date = (char *) fs_get(MESSAGE_ID_LENGTH); rfc822_date(envelope->date); /* Allow legitimate schizoids (undocumented) */ compose_smart_reply(envelope, newsgroups); if((sendnews == TRUE) && (nntp_stream != NIL)) { /* * We create a separate envelope for news posts, containing * newsgroups line, and stripping out to,cc,bcc. We don't need to, * but partitioning like this will prevent older pine clients * from reporting "bogus newsgroups". The reasons are amusing if you * look closely at c-client/rfc822.c. */ news_envelope = mail_newenvelope(); news_envelope->from = copy_address(envelope->from); news_envelope->reply_to = copy_address(envelope->reply_to); news_envelope->return_path = copy_address(envelope->return_path); news_envelope->sender = copy_address(envelope->sender); news_envelope->subject = cpystr(envelope->subject); news_envelope->message_id = cpystr(envelope->message_id); news_envelope->date = cpystr(envelope->date); if(compose->in_reply_to) { news_envelope->in_reply_to = (char *) fs_get((2 * strlen(compose->in_reply_to)) + 32); sprintf(news_envelope->in_reply_to,"%s\r\nReferences: %s", compose->in_reply_to, compose->in_reply_to); } news_envelope->newsgroups = cpystr(newsgroups); errors = nntp_mail(nntp_stream, news_envelope, body); if(errors != T ) { mm_log(MLGetLocalized(XtNmsgSendNNTPFailed,MsgSendNNTPFailed),WARN); retry = TRUE; } else mm_log(MLGetLocalized(XtNmsgNewsSent,MsgNewsSent),NIL); smtp_close(nntp_stream); } if((sendmail == TRUE) && (smtp_stream != NIL)) { /* * OK. Now we've got to see if 8-bit text is allowed, and otherwise * do some last minute patching of the message if it's got 8-bit * text. */ if((intl == TRUE) && (compose->options->send_eight == TRUE)) { if(! smtp_stream->ok_8bitmime) { mm_log(MLGetLocalized(XtNmsgSendEightFailure,MsgSendEightFailure), WARN); compose->options->send_eight = FALSE; } } if(compose->options->send_eight == TRUE) fs_give((void **) &temp_text); /* Well, we sure don't need you now */ else { if((intl == TRUE) && (currbody != NULL)) { if (temp_text == NULL) temp_text = (char *) rfc822_8bit((unsigned char *) text, (unsigned long) strlen(text), &len); currbody->encoding = ENCQUOTEDPRINTABLE; fs_give((void **) &text); currbody->contents.text = (unsigned char *) temp_text; currbody->size.bytes = (unsigned long) strlen((char *) temp_text); } iso_encode_address(envelope->from); iso_encode_address(envelope->to); iso_encode_address(envelope->cc); iso_encode_address(envelope->bcc); iso_encode_address(envelope->reply_to); iso_encode_address(envelope->return_path); if(envelope->subject) fs_give((void **) &envelope->subject); envelope->subject = iso_encode_subject(subject); } errors = smtp_mail(smtp_stream,"MAIL", envelope, body); if(errors != T ) { mm_log(MLGetLocalized(XtNmsgSendSMTPFailed,MsgSendSMTPFailed),WARN); retry = TRUE; } else mm_log(MLGetLocalized(XtNmsgMailSent,MsgMailSent),NIL); smtp_close(smtp_stream); } if(retry == FALSE) { if((sendnews == TRUE) && (sendmail == TRUE)) envelope->newsgroups = cpystr(newsgroups); log_message(compose, body, envelope); } if(sendnews == TRUE) mail_free_envelope(&news_envelope); if(sendmail == TRUE) mail_free_envelope(&envelope); /* * If the send failed, protect all our attachments. mail_free_body() * is recursive. If the first part is our text, we'll let it go, * since it will be rebuilt next time through. This also means we * don't explicity free it. It will be nuked as a result of * mail_free_body(). */ if((retry == TRUE) || (compose->options->keep_open == TRUE)) { if(attach_text == TRUE) body->contents.part->next = NIL; else body->contents.part = NIL; } else { /* Set answered flag on original message if appropriate */ if(((compose->compose_type == COMPOSE_REPLY) || (compose->compose_type == COMPOSE_REPLYALL)) && ((compose->message != NULL) && compose->message->mailstream && compose->message->msgno)) { sprintf(msgno_string,"%lu",compose->message->msgno); push_cursor(WATCH_CURSOR); mail_setflag(compose->message->mailstream, msgno_string, ANSWERED_FLAG ); mm_flags(compose->message->mailstream, compose->message->msgno); pop_cursor(); } } /* * Clean up everything and go home. */ mail_free_body(&body); /* and therefore our allocated text */ fs_give((void **) &from); fs_give((void **) &to); fs_give((void **) &newsgroups); fs_give((void **) &subject); fs_give((void **) &cc); fs_give((void **) &bcc); fs_give((void **) &mailhosts[0]); fs_give((void **) &mailhosts); fs_give((void **) &newshosts[0]); fs_give((void **) &newshosts); fs_give((void **) &default_host); if((retry == FALSE) && (compose->options->keep_open == FALSE)) { /* * Our attachments are already gone. Make sure we don't * free them a second time. */ compose->attachments = NIL; compose_close_window(w,compose,xp); } pop_cursor(); return; } /* * Called externally from mm_expunge() on an expunge event. There is no * guarantee that a compose structure exists. What we do is locate a * message structure which matches and zero it out in the compose structure. * This guarantees we won't be setting any flags on it later. There will * only be such a message structure on replies. Since these are just * pointers to messages found in the mailbox, we don't need to manage * the message numbers for higher numbered messages here. That's done * in the main window expunge loop. Be careful not to destroy the * structure before this gets called. */ #ifdef __STDC__ void compose_expunge(MAILSTREAM *mailstream, unsigned long msgno) #else void compose_expunge(mailstream,msgno) MAILSTREAM *mailstream; unsigned long msgno; #endif { MLCompose *compose; if(session->compose != NULL) { for(compose = session->compose ; compose; compose = compose->next) { if((compose->message != NULL) && (compose->message->mailstream == mailstream) && (compose->message->msgno == msgno)) compose->message = NULL; } } return; } #ifdef __STDC__ void load_compose_from_read(MLCompose *compose, Compose_Type type, Boolean news, Read_Info *read_info) #else void load_compose_from_read(compose,type,news,read_info) MLCompose *compose; Compose_Type type; Boolean news; Read_Info *read_info; #endif { char *to; char *reply_subject; char *cc; char *msgid; char *ptr1; char *ptr2; char *fulltext; char *fulleverything; PART *part; BODY *body; char *tmp; if((type == COMPOSE_NEW) || (read_info == NULL)) return; compose->compose_type = type; push_cursor(WATCH_CURSOR); switch(type) { case COMPOSE_REPLYALL: ptr1 = get_header_field_contents(HEADER_NEWSGROUPS, read_info->header); if(ptr1) { XmTextSetString(compose->window->newsgroups_text, ptr1); fs_give((void **) &ptr1); } ptr1 = get_header_field_contents(HEADER_TO,read_info->header); if(ptr1 == NULL) ptr1 = cpystr(EMPTYSTR); ptr2 = get_header_field_contents(HEADER_CC,read_info->header); if(ptr2 == NULL) ptr2 = cpystr(EMPTYSTR); cc = (char *) fs_get(strlen(ptr1) + strlen(ptr2) + 8 ); *cc = NUL_TERM; if(*ptr1 != NUL_TERM) { strcpy(cc,ptr1); if(*ptr2 != NUL_TERM) strcat(cc,", "); } if(*ptr2 != NUL_TERM) strcat(cc,ptr2); fs_give((void **) &ptr1); fs_give((void **) &ptr2); XmTextSetString(compose->window->cc_text, cc); fs_give((void **) &cc); /* fall through to set other info */ case COMPOSE_REPLY: to = get_header_field_contents(HEADER_REPLY_TO,read_info->header); if(to == NULL) to = get_header_field_contents(HEADER_FROM, read_info->header); if(to) { XmTextSetString(compose->window->to_text, to); fs_give((void **) &to); } reply_subject = get_reply_subject(read_info->header); if(reply_subject != NULL) { XmTextSetString(compose->window->subject_text, reply_subject); fs_give((void **) &reply_subject); } msgid = get_header_field_contents(HEADER_MESSAGE_ID, read_info->header); compose->in_reply_to = msgid; /* References !!! */ if(read_info->alt_text) compose->reply_text = cpystr(read_info->alt_text); else if(read_info->current_text) compose->reply_text = cpystr(read_info->current_text); compose->message = read_info->message; break; case COMPOSE_FORWARD: if(read_info->alt_text) { ptr1 = get_forward_text(read_info->alt_text); if(ptr1) { XmTextSetString(compose->window->compose_text, ptr1); fs_give((void **) &ptr1); } } else { if(read_info->current_text) { ptr1 = get_forward_text(read_info->current_text); if(ptr1) { XmTextSetString(compose->window->compose_text, ptr1); fs_give((void **) &ptr1); } } } ptr1 = get_forward_subject(read_info->header); if(ptr1) { XmTextSetString(compose->window->subject_text, ptr1); fs_give((void **) &ptr1); } break; case COMPOSE_FORWARDATTACH: if((read_info->mailstream == NULL) || (read_info->msgno == 0L)) { mm_log(MLGetLocalized(XtNmsgForwardExpunged,MsgForwardExpunged),WARN); break; } fulltext = mail_fetchtext(read_info->mailstream,read_info->msgno); if(fulltext == NULL) break; stripcr(fulltext); fulleverything = (char *) fs_get(((read_info->header) ? strlen(read_info->header) : 1) + strlen(fulltext) + 256); strcpy(fulleverything, (read_info->header) ? read_info->header : EMPTYSTR); strcat(fulleverything,LFSTR); strcat(fulleverything,fulltext); part = mail_newbody_part(); body = &part->body; body->type = TYPEMESSAGE; body->subtype = cpystr("RFC822"); body->description = get_forward_subject(read_info->header); body->encoding = ENC7BIT; body->contents.msg.text = fulleverything; compose->attachments = part; break; case COMPOSE_REMAIL: if(read_info->mailstream && read_info->msgno) { compose->remail_header = cpystr(mail_fetchheader(read_info->mailstream,read_info->msgno)); ptr1 = cpystr(mail_fetchtext(read_info->mailstream, read_info->msgno)); if(ptr1) { stripcr(ptr1); XmTextSetString(compose->window->compose_text, ptr1); fs_give((void **) &ptr1); } } break; default: break; } if((compose->options->defcc != NULL) && (*compose->options->defcc != NUL_TERM)) { ptr1 = XmTextGetString(compose->window->cc_text); if(*ptr1 != NUL_TERM) AppendText(compose->window->cc_text,", "); AppendText(compose->window->cc_text,compose->options->defcc); fs_give((void **) &ptr1); } if((compose->options->defbcc != NULL) && (*compose->options->defbcc != NUL_TERM)) { ptr1 = XmTextGetString(compose->window->bcc_text); if(*ptr1 != NUL_TERM) AppendText(compose->window->bcc_text,", "); AppendText(compose->window->bcc_text,compose->options->defbcc); fs_give((void **) &ptr1); } pop_cursor(); return; } #ifdef __STDC__ void load_compose_info(MLCompose *compose, Compose_Type type, Boolean news, Lview *lview, Message *message) #else void load_compose_info(compose,type, news, lview, message) MLCompose *compose; Compose_Type type; Boolean news; Lview *lview; Message *message; #endif { char *tmp; char *to; char *reply_subject; char *cc; char *msgid; char *ptr1; char *ptr2; char *fulleverything; PART *oldpart; PART *part; BODY *body; char *fetched_header = NULL; char *fetched_text = NULL; Message_List *message_list; compose->compose_type = type; push_cursor(WATCH_CURSOR); if(message) { fetched_header = cpystr(mail_fetchheader(message->mailstream, message->msgno)); stripcr(fetched_header); if(fetched_header[strlen(fetched_header) - 1] == LFCHAR) fetched_header[strlen(fetched_header) - 1] = NUL_TERM; fetched_text = cpystr(mail_fetchtext(message->mailstream, message->msgno)); stripcr(fetched_text); } switch(type) { case COMPOSE_REPLYALL: ptr1 = get_header_field_contents(HEADER_NEWSGROUPS, fetched_header); if(ptr1) { XmTextSetString(compose->window->newsgroups_text,ptr1); fs_give((void **) &ptr1); } ptr1 = get_header_field_contents(HEADER_TO,fetched_header); if(ptr1 == NULL) ptr1 = cpystr(EMPTYSTR); ptr2 = get_header_field_contents(HEADER_CC,fetched_header); if(ptr2 == NULL) ptr2 = cpystr(EMPTYSTR); cc = (char *) fs_get(strlen(ptr1) + strlen(ptr2) + 8 ); *cc = NUL_TERM; if(*ptr1 != NUL_TERM) { strcpy(cc,ptr1); if(*ptr2 != NUL_TERM) strcat(cc,", "); } if(*ptr2 != NUL_TERM) strcat(cc,ptr2); fs_give((void **) &ptr1); fs_give((void **) &ptr2); XmTextSetString(compose->window->cc_text,cc); fs_give((void **) &cc); /* fall through to set other info */ case COMPOSE_REPLY: to = get_header_field_contents(HEADER_REPLY_TO,fetched_header); if(to == NULL) to = get_header_field_contents(HEADER_FROM, fetched_header); if(to) { XmTextSetString(compose->window->to_text, to); fs_give((void **) &to); } reply_subject = get_reply_subject(fetched_header); if(reply_subject) { XmTextSetString(compose->window->subject_text, reply_subject); fs_give((void **) &reply_subject); } msgid = get_header_field_contents(HEADER_MESSAGE_ID, fetched_header); compose->in_reply_to = msgid; if(fetched_text) compose->reply_text = cpystr(fetched_text); compose->message = message; break; case COMPOSE_FORWARD: get_multi_forward_info(lview,compose); break; case COMPOSE_FORWARDATTACH: for(message_list = lview->message_list; message_list; message_list = message_list->next) { if(message_list->selected == TRUE) { if(fetched_header) fs_give((void **) &fetched_header); if(fetched_text) fs_give((void **) &fetched_text); fetched_header = cpystr(mail_fetchheader(message_list->message->mailstream, message_list->message->msgno)); stripcr(fetched_header); if(fetched_header[strlen(fetched_header) - 1] == LFCHAR) fetched_header[strlen(fetched_header) - 1] = NUL_TERM; fetched_text = cpystr(mail_fetchtext(message_list->message->mailstream, message_list->message->msgno)); stripcr(fetched_text); fulleverything = (char *) fs_get(strlen(fetched_header) + strlen(fetched_text) + 256); strcpy(fulleverything,fetched_header); strcat(fulleverything,LFSTR); strcat(fulleverything,fetched_text); part = mail_newbody_part(); body = &part->body; body->type = TYPEMESSAGE; body->subtype = cpystr("RFC822"); body->description = get_forward_subject(fetched_header); body->encoding = ENC7BIT; body->contents.msg.text = fulleverything; if(compose->attachments == NULL) compose->attachments = part; else { for(oldpart = compose->attachments; oldpart->next; oldpart = oldpart->next) ; oldpart->next = part; } fs_give((void **) &fetched_header); fs_give((void **) &fetched_text); } } break; case COMPOSE_REMAIL: compose->message = message; if(fetched_header) compose->remail_header = cpystr(fetched_header); if(fetched_text) XmTextSetString(compose->window->compose_text,fetched_text); break; default: break; } if(fetched_header) fs_give((void **) &fetched_header); if(fetched_text) fs_give((void **) &fetched_text); if((compose->options->defcc != NULL) && (*compose->options->defcc != NUL_TERM)) { ptr1 = XmTextGetString(compose->window->cc_text); if(*ptr1 != NUL_TERM) AppendText(compose->window->cc_text,", "); AppendText(compose->window->cc_text,compose->options->defcc); fs_give((void **) &ptr1); } if((compose->options->defbcc != NULL) && (*compose->options->defbcc != NUL_TERM)) { ptr1 = XmTextGetString(compose->window->bcc_text); if(*ptr1 != NUL_TERM) AppendText(compose->window->bcc_text,", "); AppendText(compose->window->bcc_text,compose->options->defbcc); fs_give((void **) &ptr1); } pop_cursor(); return; } #ifdef __STDC__ void get_multi_forward_info(Lview *lview, MLCompose *compose) #else void get_multi_forward_info(lview,compose) Lview *lview; MLCompose *compose; #endif { Message_List *message_list; unsigned long count = 0L; Message *message = NULL; char *old_header = NULL; char *old_text = NULL; char *new_header = NULL; char *new_text = NULL; char *tmp_header = NULL; char *tmp_text = NULL; char *fetched_header = NULL; char *fetched_text = NULL; char *ret = NULL; char *foo = NULL; for(message_list = lview->message_list; message_list; message_list = message_list->next) { if(message_list->selected) { message = message_list->message; count ++; } } if(count == 0) return; if((count == 1) && (message)) { fetched_header = cpystr(mail_fetchheader(message->mailstream, message->msgno)); stripcr(fetched_header); if(fetched_header[strlen(fetched_header) - 1] == LFCHAR) fetched_header[strlen(fetched_header) - 1] = NUL_TERM; fetched_text = cpystr(mail_fetchtext(message->mailstream, message->msgno)); stripcr(fetched_text); foo = get_forward_text(fetched_text); XmTextSetString(compose->window->compose_text, foo); fs_give((void **) &foo); foo = get_forward_subject(fetched_header); XmTextSetString(compose->window->subject_text,foo); fs_give((void **) &foo); fs_give((void **) &fetched_header); fs_give((void **) &fetched_text); return; } count = 0; XmTextSetString(compose->window->subject_text, MLGetLocalized(XtNstrMultiForwardSubject, StrMultiForwardSubject)); old_header = cpystr(MLGetLocalized(XtNstrMultiForwardHeader, StrMultiForwardHeader)); old_text = cpystr(EMPTYSTR); for(message_list = lview->message_list; message_list; message_list = message_list->next) { if(message_list->selected) { message = message_list->message; count ++; fetched_header = cpystr(mail_fetchheader(message->mailstream, message->msgno)); stripcr(fetched_header); if(fetched_header[strlen(fetched_header) - 1] == LFCHAR) fetched_header[strlen(fetched_header) - 1] = NUL_TERM; tmp_header = get_short_forward_line(fetched_header,count); new_header = (char *)fs_get(strlen(old_header) + strlen(tmp_header) + 1); strcpy(new_header,old_header); strcat(new_header,tmp_header); fs_give((void **) &old_header); fs_give((void **) &tmp_header); fs_give((void **) &fetched_header); old_header = new_header; fetched_text = cpystr(mail_fetchtext(message->mailstream, message->msgno)); stripcr(fetched_text); tmp_text = get_forward_text(fetched_text); new_text = (char *) fs_get(strlen(old_text) + strlen(tmp_text) + 2); strcpy(new_text,old_text); strcat(new_text,LFSTR); strcat(new_text,tmp_text); fs_give((void **) &old_text); fs_give((void **) &tmp_text); fs_give((void **) &fetched_text); old_text = new_text; } } ret = (char *) fs_get(strlen(old_header) + strlen(old_text) + 1); strcpy(ret,old_header); strcat(ret,old_text); fs_give((void **) &old_header); fs_give((void **) &old_text); XmTextSetString(compose->window->compose_text,ret); fs_give((void **) &ret); return; } #ifdef __STDC__ void compose_help(Widget w, MLCompose *compose, XtPointer xp) #else void compose_help(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { help(compose->window->shell, COMPOSEHELPFILE); return; } /* Option setting callbacks. */ #ifdef __STDC__ void compose_keep_open(Widget w, MLCompose *compose, XtPointer xp) #else void compose_keep_open(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { if((compose != NULL) && (compose->options != NULL)) { compose->options->keep_open = TRUE; } return; } #ifdef __STDC__ void compose_eight(Widget w, MLCompose *compose, XtPointer xp) #else void compose_eight(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { if((compose != NULL) && (compose->options != NULL)) { compose->options->send_eight = TRUE; } return; } #ifdef __STDC__ void compose_seven(Widget w, MLCompose *compose, XtPointer xp) #else void compose_seven(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { if((compose != NULL) && (compose->options != NULL)) { compose->options->send_eight = FALSE; } return; } /* * Turn on the mail debugging flag. We can also do it globally * from preferences.smtp_debug. This sets it for the current * message only. There is no way to turn it off again. */ #ifdef __STDC__ void compose_watch_delivery(Widget w, MLCompose *compose, XtPointer xp) #else void compose_watch_delivery(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { if((compose != NULL) && (compose->options != NULL)) { compose->options->verbose = TRUE; } return; } #ifdef __STDC__ struct mail_body_parameter *copy_params(struct mail_body_parameter *src, Boolean intl) #else struct mail_body_parameter *copy_params(src, intl) struct mail_body_parameter *src; Boolean intl; #endif { struct mail_body_parameter *curr; struct mail_body_parameter *new; struct mail_body_parameter *prev = NULL; struct mail_body_parameter *ret = NULL; if(src == NULL) return(NULL); for(curr = src; curr; curr = curr->next) { /* No 8-bit characters were found. Remove any charset value * so as to default to us-ascii. This is called for in the * MIME specification. */ if((intl == FALSE) && (curr != NULL) && (curr->attribute != NULL) && ((strcasecmp(curr->attribute,"charset")) == STRMATCH)) continue; new = mail_newbody_parameter(); new->attribute = cpystr(curr->attribute); new->value = cpystr(curr->value); if(ret == NULL) ret = new; if(prev) prev->next = new; prev = new; } return(ret); } #ifdef __STDC__ void fix_empty_attachments(MLCompose *compose) #else void fix_empty_attachments(compose) MLCompose *compose; #endif { Part_List *part_list; BODY *body; PART *part; BODY *newbody; Boolean changed = FALSE; for(part_list = compose->part_list; part_list; part_list = part_list->next) { body = &(part_list->part->body); if((body->type == TYPEMULTIPART) && (body->contents.part == NULL)) { /* * Somebody tried to send an empty part. It would be rather * painful to try and prune it, so we'll gratuitously supply * a part for them. Otherwise, the c-client will core dump. * */ part = mail_newbody_part(); body->contents.part = part; newbody = &part->body; newbody->type = TYPETEXT; newbody->encoding = ENC7BIT; newbody->description = cpystr(MLGetLocalized(XtNstrFakePart, StrFakePart)); newbody->subtype = cpystr("plain"); newbody->contents.text = (unsigned char *) cpystr(EMPTYSTR); newbody->size.bytes = 0; changed = TRUE; } } if(changed == TRUE) { mm_log(MLGetLocalized(XtNmsgEmptyMultipart,MsgEmptyMultipart),WARN); make_attachment_list(compose, FALSE); } return; } #ifdef __STDC__ void log_message(MLCompose *compose, BODY *body, ENVELOPE *envelope) #else void log_message(compose, body, envelope) MLCompose *compose; BODY *body; ENVELOPE *envelope; #endif { extern STRINGDRIVER mail_string; STRING bs; char *mailboxname; char tmp[16 * FILEBUFFLEN]; char tmpfile[MAXPATHLEN]; char log[FILEBUFFLEN]; Binary_Buffer *binary_buffer; FILE *fp; Server_Config *config; char *host; Boolean changed = FALSE; /* ignored */ if((compose != NULL) && (compose->options != NULL)) { if((*compose->options->outlog == NUL_TERM) || (compose->options->message_log == FALSE)) return; mailboxname = fix_netmailboxpath(compose->options->outlog,&changed); if(compose->options->log_attachments == FALSE) { log_short_message(compose,mailboxname,body,envelope); return; } tmpnam(tmpfile); if((fp = fopen(tmpfile,"w")) == NULL) { sprintf(log,MLGetLocalized(XtNmsgCannotWriteFile,MsgCannotWriteFile), tmpfile); mm_log(log,WARN); fs_give((void **) &mailboxname); return; } chmod(tmpfile,S_IRWXU); rfc822_output(tmp,envelope, body, ml_file_soutr, fp); fclose(fp); binary_buffer = load_binary_file(tmpfile); unlink(tmpfile); if(binary_buffer) { if(binary_buffer->data) { INIT(&bs,mail_string,binary_buffer->data, binary_buffer->length); if((mail_append_full(NIL,mailboxname, SEEN_FLAG, NULL, &bs)) == NIL) mm_log(MLGetLocalized(XtNmsgAppendFailed,MsgAppendFailed),WARN); } free_binary_buffer(binary_buffer); } } return; } #ifdef __STDC__ long ml_file_soutr(void *stream, char *s) #else long ml_file_soutr(stream,s) void *stream; char *s; #endif { FILE *fp = stream; char c, *t; if (s[0] == '.') fputs(".",fp); /* find lines beginning with a "." */ while (t = ML_Strstr (s,"\015\012.")) { c = *(t += 3); /* remember next character after "." */ *t = '\0'; /* tie off string */ /* output prefix */ if ((fputs(s,fp)) == EOF) return NIL; *t = c; /* restore delimiter */ s = t - 1; /* push pointer up to the "." */ } if(*s) { if((fputs(s,fp)) == EOF) return(NIL); else return(T); } else return(T); } #ifdef __STDC__ void cat4(char *dest, char *s1, char *s2, char *s3, char *s4) #else void cat4(dest,s1,s2,s3,s4) char *dest; char *s1; char *s2; char *s3; char *s4; #endif { strcat(dest,s1); strcat(dest,s2); strcat(dest,s3); strcat(dest,s4); return; } #ifdef __STDC__ void log_short_message(MLCompose *compose, char *mailboxname, BODY *body, ENVELOPE *envelope) #else void log_short_message(compose, mailboxname, body, envelope) MLCompose *compose; char *mailboxname; BODY *body; ENVELOPE *envelope; #endif { extern STRINGDRIVER mail_string; STRING bs; char *from; char *newsgroups; char *to; char *subject; char *cc; char *bcc; char *text; char *date; char *temp_text; char *bigbuf; char *ret; Server_Config *server_config; char *host; from = cpystr(compose->options->replyto); newsgroups = GetTextField(compose->window->newsgroups_text); to = GetTextField(compose->window->to_text); subject = GetTextField(compose->window->subject_text); cc = GetTextField(compose->window->cc_text); bcc = GetTextField(compose->window->bcc_text); temp_text = XmTextGetString(compose->window->compose_text); date = (char *) fs_get(MESSAGE_ID_LENGTH); rfc822_date(date); if(compose->options->word_wrap == TRUE) text = wrap_text(temp_text, COMPOSEWIDTH - 1); else text = cpystr(temp_text); fs_give((void **) &temp_text); bigbuf = (char *) fs_get( ((from) ? strlen(from) : 0) + ((newsgroups) ? strlen(newsgroups) : 0) + ((to) ? strlen(to) : 0) + ((subject) ? strlen(subject) : 0) + ((cc) ? strlen(cc) : 0) + ((bcc) ? strlen(bcc) : 0) + ((date) ? strlen(date) : 0) + ((envelope->in_reply_to) ? strlen(envelope->in_reply_to) : 0) + ((envelope->message_id) ? strlen(envelope->message_id) : 0) + ((text) ? strlen(text) : 0) + 512); *bigbuf = NUL_TERM; if(from) { if(*from) cat4(bigbuf,HEADER_FROM,SPACESTR,from,LFSTR); fs_give((void **) &from); } if(newsgroups) { if(*newsgroups) cat4(bigbuf,HEADER_NEWSGROUPS,SPACESTR,newsgroups,LFSTR); fs_give((void **) &newsgroups); } if(to) { if(*to) cat4(bigbuf,HEADER_TO,SPACESTR,to,LFSTR); fs_give((void **) &to); } if(subject) { if(*subject) cat4(bigbuf,HEADER_SUBJECT,SPACESTR,subject,LFSTR); fs_give((void **) &subject); } if(cc) { if(*cc) cat4(bigbuf,HEADER_CC,SPACESTR,cc,LFSTR); fs_give((void **) &cc); } if(bcc) { if(*bcc) cat4(bigbuf,HEADER_BCC,SPACESTR,bcc,LFSTR); fs_give((void **) &bcc); } if(date) { if(*date) cat4(bigbuf,HEADER_DATE,SPACESTR,date,LFSTR); fs_give((void **) &date); } if(envelope->in_reply_to) { if(*envelope->in_reply_to) cat4(bigbuf,HEADER_IN_REPLY_TO,SPACESTR,envelope->in_reply_to,LFSTR); } if(envelope->message_id) { if(*envelope->message_id) cat4(bigbuf,HEADER_MESSAGE_ID,SPACESTR,envelope->message_id,LFSTR); } strcat(bigbuf,LFSTR); if(text) { if(*text) strcat(bigbuf,text); strcat(bigbuf,LFSTR); fs_give((void **) &text); } ret = lftocrlf(bigbuf); fs_give((void **) &bigbuf); if(ret) { INIT(&bs,mail_string,ret,strlen(ret)); if((mail_append_full(NIL, mailboxname, SEEN_FLAG, NULL, &bs)) == NIL) mm_log(MLGetLocalized(XtNmsgAppendFailed,MsgAppendFailed),WARN); fs_give((void **) &ret); } if(mailboxname) fs_give((void **) &mailboxname); return; } #ifdef __STDC__ char *param_to_str(PARAMETER *parameter) #else char *param_to_str(parameter) PARAMETER *parameter; #endif { char buffer[FILEBUFFLEN]; PARAMETER *p; if(parameter == NULL) return(cpystr(EMPTYSTR)); strcpy(buffer,EMPTYSTR); for(p = parameter; p; p = p->next) { if((p->attribute == NULL) || (p->value == NULL)) continue; if(*buffer != NUL_TERM) strcat(buffer,SPACESTR); strcat(buffer,p->attribute); strcat(buffer,EQUALSTR); strcat(buffer,p->value); } return(cpystr(buffer)); } #ifdef __STDC__ PARAMETER *str_to_param(char *str) #else PARAMETER *str_to_param(str) char *str; #endif { char *p; char *ptr; char *last = str; PARAMETER *parameter = NULL; PARAMETER *first = NULL; PARAMETER *lastp = NULL; Boolean reached_end = FALSE; Boolean bad_input = FALSE; if((str == NULL) || (*str == NUL_TERM)) return(NULL); for(ptr = str; *ptr != NUL_TERM ; ptr ++) { if(reached_end == TRUE) break; if(*ptr != EQUALCHAR) continue; *ptr = NUL_TERM; ptr ++; parameter = mail_newbody_parameter(); parameter->attribute = cpystr(last); p = ptr; if(*p == DQUOTECHAR) { p ++; while((*p != NUL_TERM) && (*p != DQUOTECHAR)) p ++; while((*p != NUL_TERM) && (*p != SPACECHAR)) p ++; } else { while ((*p != NUL_TERM) && (*p != SPACECHAR)) p ++; } if(*p == NUL_TERM) reached_end = TRUE; *p = NUL_TERM; parameter->value = cpystr(ptr); if(first == NULL) { first = parameter; lastp = parameter; } else { lastp->next = parameter; lastp = parameter; } if(reached_end == TRUE) break; else { last = p + 1; ptr = p + 1; while((*last != NUL_TERM) && (isspace(*last))) last ++; if(*last == NUL_TERM) break; } } /* Now check for bad input.... */ for(parameter = first; parameter != NULL; parameter = parameter->next) { if((parameter->attribute == NULL) || (parameter->value == NULL)) bad_input = TRUE; } if(bad_input) { mm_log(MLGetLocalized(XtNmsgInvalidParams,MsgInvalidParams),ERROR); mail_free_body_parameter(&first); } return(first); } #ifdef __STDC__ void compose_delete_part(Widget w, MLCompose *compose, XtPointer xp) #else void compose_delete_part(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { Part_List *part_list; BODY *body = NULL; if((compose->window->attach_list_selection == 0) || (compose->part_list == NULL)) return; /* point to the Part_List of the selected part.*/ for(part_list = compose->part_list; part_list->partnumber != compose->window->attach_list_selection; part_list = part_list->next); /* First see if it's a multipart which still has contents */ body = &(part_list->part->body); if(body->type == TYPEMULTIPART && (body->contents.part != NULL)) { mm_log(MLGetLocalized(XtNmsgNonEmptyMulti,MsgNonEmptyMulti),WARN); return; } /* first part in our attachment list */ if(part_list->part == compose->attachments) { compose->attachments = part_list->part->next; part_list->part->next = NULL; mail_free_body_part(&part_list->part); make_attachment_list(compose, FALSE); return; } /* Some other part. See if our previous neighbor points to us. */ if((part_list->prev) && (part_list->prev->part->next == part_list->part)) { part_list->prev->part->next = part_list->part->next; part_list->part->next = NULL; } else { /* Hmmm. Heirarchical. Find the parent. */ body = (part_list->prev) ? &(part_list->prev->part->body) : NULL; if((body) && (body->type == TYPEMULTIPART)) body->contents.part = part_list->part->next; part_list->part->next = NULL; } mail_free_body_part(&part_list->part); make_attachment_list(compose, FALSE); return; } /* * Callback when an item in the attachment list is selected. */ #ifdef __STDC__ void select_attach(Widget w, MLCompose *compose, XmListCallbackStruct *xp) #else void select_attach(w,compose,xp) Widget w; MLCompose *compose; XmListCallbackStruct *xp; #endif { if(xp->item_position == compose->window->attach_list_selection) { compose->window->attach_list_selection = 0; compose->window->buttonstate |= BTN_NOATTACHSELECT; } else { compose->window->attach_list_selection = xp->item_position; compose->window->buttonstate &= ~(BTN_NOATTACHSELECT); } compose_check_buttons(compose); return; } #ifdef __STDC__ void double_click_attach(Widget w, MLCompose *compose, XmListCallbackStruct *xp) #else void double_click_attach(w,compose,xp) Widget w; MLCompose *compose; XmListCallbackStruct *xp; #endif { Part_List *part_list; BODY *body; if(! xp->item_position) return; for(part_list = compose->part_list; part_list && part_list->partnumber != xp->item_position; part_list = part_list->next); if(! part_list) return; /* Make sure the window shows it as selected */ XmListDeselectAllItems(compose->window->attach_list); compose->window->attach_list_selection = xp->item_position; compose->window->buttonstate &= ~(BTN_NOATTACHSELECT); XmListSelectPos(compose->window->attach_list,xp->item_position,FALSE); compose_check_buttons(compose); body = &(part_list->part->body); /* invoke message handler */ show_mime(compose->window->shell, body, FALSE); return; } #ifdef __STDC__ void make_attachment_list(MLCompose *compose, Boolean init) #else void make_attachment_list(compose, init) MLCompose *compose; Boolean init; #endif { if(compose != NULL) { /* Erase current list contents and start over */ XmListDeselectAllItems(compose->window->attach_list); XmListDeleteAllItems(compose->window->attach_list); compose->window->attach_list_selection = 0; compose->window->buttonstate |= BTN_NOATTACHSELECT; /* No contents. Check buttons and get outa' here */ if(compose->attachments == NULL) { compose->window->buttonstate |= BTN_NOATTACH; compose_check_buttons(compose); return; } if(compose->part_list) { destroy_part_list(compose->part_list); } compose->part_list = NULL; /* * Recursively add strings to the attachment list widget * and add to our part_list structure. We use this to look up * specific parts from the list management functions without having * to go through all this recursive hullabaloo all over again. */ add_attach_strings(compose->window->attach_list, compose, compose->attachments,0); compose->window->buttonstate &= ~(BTN_NOATTACH); compose_check_buttons(compose); } return; } #ifdef __STDC__ void destroy_part_list(Part_List *part_list) #else void destroy_part_list(part_list) Part_List *part_list; #endif { if(part_list == NULL) return; destroy_part_list(part_list->next); if(part_list->partstr) fs_give((void **) &part_list->partstr); fs_give((void **) &part_list); part_list = NULL; return; } #ifdef __STDC__ void add_attach_strings(Widget wid, MLCompose *compose, PART *part, int level) #else void add_attach_strings(wid,compose,part,level) Widget wid; MLCompose *compose; PART *part; int level; #endif { int len; XmString xstr; PART *curr; char buffer[FILEBUFFLEN]; Part_List *part_list; Part_List *curr_part_list; struct mail_body_parameter *params; if(part == NULL) return; for(curr = part; curr; curr = curr->next) { strcpy(buffer,EMPTYSTR); for(len = 0; len < level; len ++) strcat(buffer,SPACESTR); strcat(buffer,type_to_name(curr->body.type)); strcat(buffer,TYPE_SEPARATOR_STR); strcat(buffer,(curr->body.subtype) ? curr->body.subtype : NOSUBTYPE ); for(len = strlen(buffer); len < (COMPOSEWIDTH/2); len ++) strcat(buffer,SPACESTR); strncat(buffer, (curr->body.description) ? curr->body.description : EMPTYSTR, COMPOSEWIDTH); buffer[COMPOSEWIDTH - 2] = NUL_TERM; for(params = curr->body.parameter; params; params = params->next) { if((int) (strlen(buffer) + strlen(params->attribute) + strlen(params->value) + 2) >= FILEBUFFLEN) break; strcat(buffer,SPACESTR); strcat(buffer,params->attribute); strcat(buffer,"="); strcat(buffer,params->value); } xstr = XmStringCreateSimple(buffer); XmListAddItemUnselected(wid,xstr,0); XmStringFree(xstr); part_list = (Part_List *) fs_get(sizeof(Part_List)); part_list->next = NULL; part_list->part = curr; part_list->partstr = NULL; if(compose->part_list == NULL) { compose->part_list = part_list; part_list->partnumber = 1; part_list->prev = NULL; } else { for(curr_part_list = compose->part_list; curr_part_list->next; curr_part_list = curr_part_list->next); curr_part_list->next = part_list; part_list->prev = curr_part_list; part_list->partnumber = curr_part_list->partnumber + 1; } if(curr->body.type == TYPEMULTIPART) add_attach_strings(wid,compose,curr->body.contents.part,level+1); } return; } #ifdef __STDC__ void compose_insert_file(Widget w, MLCompose *compose, XtPointer xp) #else void compose_insert_file(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { char *filename; Binary_Buffer *binary_buffer; filename = file_select(compose->window->shell, NULL, NULL, NULL, FALSE, NULL); if(filename == NULL) return; push_cursor(WATCH_CURSOR); binary_buffer = load_binary_file(filename); if(binary_buffer) { text_blast(compose->window->compose_text,(char *)binary_buffer->data); free_binary_buffer(binary_buffer); } fs_give((void **) &filename); pop_cursor(); return; } /* * Append signature file into current text window and call * send_message(). We throw in an extra linefeed between the two * just in case the last line of the message doesn't have one. */ #ifdef __STDC__ void compose_send_autograph(Widget w, MLCompose *compose, XtPointer xp) #else void compose_send_autograph(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { FILE *fp; char *filename; char buffer[FILEBUFFLEN]; filename = cpystr(compose->options->sigfile); if((*filename != NUL_TERM) && (fp = fopen(filename,"r")) != NULL) { AppendText(compose->window->compose_text,LFSTR); while((fgets(buffer,sizeof(buffer),fp)) != NULL) AppendText(compose->window->compose_text,buffer); fclose(fp); } fs_give((void **) &filename); send_message(w,compose,xp); return; } #ifdef __STDC__ void compose_attach_file(Widget w, MLCompose *compose, XtPointer xp) #else void compose_attach_file(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { char *filename = NULL; Binary_Buffer *binary_buffer; PART *part; BODY *body; Boolean auto_attach; Boolean keep_going; filename = file_select(compose->window->shell, NULL, NULL, NULL, FALSE, NULL); if(filename == NULL) return; binary_buffer = load_binary_file(filename); if(binary_buffer) { part = mail_newbody_part(); body = &part->body; set_default_attach_type(body,filename); if((auto_attach = get_type_from_suffix(body,filename)) == FALSE) keep_going = create_mime_attach_window(compose->window->shell,body,FALSE); if(auto_attach || keep_going) link_attachment(compose,part,body,binary_buffer); else mail_free_body_part(&part); free_binary_buffer(binary_buffer); } fs_give((void **) &filename); return; } #ifdef __STDC__ void compose_attach_multi(Widget w, MLCompose *compose, XtPointer xp) #else void compose_attach_multi(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { PART *part; BODY *body; part = mail_newbody_part(); body = &part->body; body->type = TYPEMULTIPART; body->subtype = cpystr("mixed"); if(create_mime_attach_window(compose->window->shell,body,TRUE)) link_attachment(compose,part,body,NULL); else mail_free_body_part(&part); return; } #ifdef __STDC__ void compose_createattach(Widget w, MLCompose *compose, XtPointer xp) #else void compose_createattach(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { PART *part; BODY *body; Binary_Buffer *binary_buffer; part = mail_newbody_part(); body = &part->body; binary_buffer = create_mime_compose_window(compose->window->shell,body); if(binary_buffer) { link_attachment(compose,part,body,binary_buffer); free_binary_buffer(binary_buffer); } else mail_free_body_part(&part); return; } /* * We've been called by an address text field widget. At least that's the * assumption, so don't try and change it. All we have is the widget. * It contains something presumably that we will have to complete from * the address book. But it might contain other addresses, and the one to be * completed could be anywhere. We presume that it is under the cursor. * We then split up the string into three parts. The part before the current * word (comma delimited), and anything afterward (delimited by comma or a * space). Any of these parts might be empty. After we extract our pattern, * we look it up, and replace it with the address book address. More on * that later. We then combine it with any or all of the other parts, and * make sure we have comma delimiters (plus a gratuitous space) between * all the fields. On failure we leave it alone, and advance to the next * tab group, since the most likely key binding for this will be a tab key. * Therefore, the tab completes, if possible, and in all other cases moves to * the next tab group. */ #ifdef __STDC__ void complete_address(Widget w, XtPointer xp) #else void complete_address(w,xp) Widget w; XtPointer xp; #endif { char *text = GetTextField(w); XmTextPosition pos = XmTextGetInsertionPosition(w); char *begin = NULL; char *end = NULL; char *pattern = NULL; char *lookup = NULL; XmTextPosition newpos = 0; Boolean found = FALSE; if(*text == NUL_TERM) { fs_give((void **) &text); XmProcessTraversal(w,XmTRAVERSE_NEXT_TAB_GROUP); return; } /* point to current position. */ pattern = text + ((pos > 0) ? (pos - 1) : 0 ); /* find the beginning of this address */ while((pattern > text) && (*pattern != ',')) pattern --; /* We're at the beginning */ if(pattern == text) { begin = NULL; } /* * Not the beginning, so set the begin pointer to it, * tie it off, and point pattern just beyond it. */ else { *pattern = NUL_TERM; pattern = first_nonwhite(pattern + 1); begin = text; } /* * find any subsequent addresses. If we find one, tie off * our pattern string, and point end at the next address. */ end = strpbrk(pattern,", "); if(end) { *end = NUL_TERM; end = first_nonwhite(end + 1); } /* * Try and match it. If we do, rebuild the visible text. Set the * cursor at the end of the address we just completed. */ if((lookup = lookup_group(pattern)) != NULL) { XmTextSetString(w,(begin) ? begin : EMPTYSTR); AppendText(w,(begin) ? ", " : EMPTYSTR ); AppendText(w,lookup); newpos = XmTextGetInsertionPosition(w); if(end) { AppendText(w,", "); AppendText(w,end); } XmTextSetInsertionPosition(w,newpos); fs_give((void **) &lookup); found = TRUE; } else { if((lookup = lookup_address(pattern)) != NULL) { XmTextSetString(w,(begin) ? begin : EMPTYSTR); AppendText(w,(begin) ? ", " : EMPTYSTR ); AppendText(w,lookup); newpos = XmTextGetInsertionPosition(w); if(end) { AppendText(w,", "); AppendText(w,end); } XmTextSetInsertionPosition(w,newpos); fs_give((void **) &lookup); found = TRUE; } } if(found == FALSE) XmProcessTraversal(w,XmTRAVERSE_NEXT_TAB_GROUP); fs_give((void **) &text); return; } #ifdef __STDC__ char *lookup_address(char *str) #else char *lookup_address(str) char *str; #endif { int cnt = 0; Address_Book_Info *address_book_info; Address_Book_Info *saved = NULL; for(address_book_info = session->addresses; address_book_info ; address_book_info = address_book_info->prev) { if((strcasecmp((char *) address_book_info->name,str)) == STRMATCH) { /* Exact match. Use it. */ cnt = 1; saved = address_book_info; break; } else { if((strncasecmp((char *) address_book_info->name, str,strlen(str))) == STRMATCH) { cnt ++; saved = address_book_info; } } } if(cnt == 1) return(cpystr((char *) saved->address)); if(cnt > 1) /* Not completed */ return(address_popup(str)); return(NULL); } #ifdef __STDC__ char *lookup_group(char *str) #else char *lookup_group(str) char *str; #endif { char buffer[FILEBUFFLEN]; char *ptr; char *end; char *result = NULL; char *now = NULL; Address_Book_Info *address_book_info; for(address_book_info = session->addresses; address_book_info ; address_book_info = address_book_info->prev) { if((address_book_info->groups == NULL) || (*address_book_info->groups == NUL_TERM)) continue; strcpy(buffer,(char *) address_book_info->groups); ptr = end = buffer; while((*ptr != NUL_TERM) && (end)) { if((end = strpbrk(ptr,", ")) != NULL) { *end = NUL_TERM; end ++; } if((strcasecmp(ptr,str)) == STRMATCH) { if(result) { now = fs_get(strlen(result) + ((address_book_info->address) ? strlen((char *) address_book_info->address) : 1) + 4); strcpy(now,result); strcat(now,", "); strcat(now,(address_book_info->address) ? (char *) address_book_info->address : EMPTYSTR); fs_give((void **) &result); result = now; } else result = cpystr((address_book_info->address) ? (char *) address_book_info->address : EMPTYSTR); } if(end) { ptr = end; while((*ptr != NUL_TERM) && ((*ptr == SPACECHAR) || (*ptr == ','))) ptr ++; } } } return(result); } #ifdef __STDC__ char *address_popup(char *str) #else char *address_popup(str) char *str; #endif { XBell(display, 500); return(NULL); } #ifdef __STDC__ void generate_subject(Widget w, MLCompose *compose, XtPointer xp) #else void generate_subject(w, compose, xp) Widget w; MLCompose *compose; XtPointer xp; #endif { Binary_Buffer *binary_buffer; unsigned char *ptr; silent_pipe = TRUE; if((access(PATH_FORTUNE, X_OK)) == SYSCALL_SUCCESS) { binary_buffer = read_from_pipe(FORTUNE_CMD); if(binary_buffer) { if(binary_buffer->data) { for(ptr = binary_buffer->data; *ptr != NUL_TERM; ptr ++) if((*ptr == LFCHAR) || (*ptr == TABCHAR)) *ptr = SPACECHAR; XmTextSetString(compose->window->subject_text, binary_buffer->data); } free_binary_buffer(binary_buffer); } } silent_pipe = FALSE; return; } #ifdef __STDC__ void compose_spell(Widget w, MLCompose *compose, XtPointer xp) #else void compose_spell(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { FILE *fp = NULL; char *text = NULL; String_List *string_list = NULL; String_List *prev = NULL; String_List *base = NULL; char *tmp_file = NULL; char *otext = NULL; Binary_Buffer *bb = NULL; char filename[MAXPATHLEN]; char buffer[FILEBUFFLEN]; char command[FILEBUFFLEN]; int count = 0; Boolean has_stop = FALSE; if(access(SPELLSTOPFILE,R_OK) == SYSCALL_SUCCESS) has_stop = TRUE; if(preferences.useIspell == FALSE) { if((compose->spellwindow != NULL) && (compose->spellwindow->is_realized == TRUE)) { de_iconify(compose->spellwindow->shell); return; } } otext = XmTextGetString(compose->window->compose_text); if(otext == NULL) return; if(*otext == NUL_TERM) { fs_give((void **) &otext); return; } /* Just in case they didn't end the message properly.... */ text = (char *) fs_get(strlen(otext) + 8); strcpy(text,otext); strcat(text,LFSTR); fs_give((void **) &otext); tmp_file = (char *) tmpnam(filename); if(preferences.useIspell == TRUE) { /* run ispell in an xterm */ if((fp = fopen(tmp_file,"w")) != NULL) { (void) chmod(tmp_file,S_IRWXU); fwrite(text,strlen(text),1,fp); fclose(fp); sprintf(command,ISPELL_COMMAND,tmp_file); XtVaSetValues(compose->window->compose_text,XmNeditable, FALSE, NULL); compose->in_ispell = TRUE; if((write_to_pipe(command,NULL, NULL, 0)) == SYSCALL_SUCCESS) { bb = load_binary_file(tmp_file); if(bb != NULL) { if(bb->data != NULL) XmTextSetString(compose->window->compose_text,(char *)bb->data); free_binary_buffer(bb); } } XtVaSetValues(compose->window->compose_text,XmNeditable, TRUE, NULL); compose->in_ispell = FALSE; } else { fs_give((void **) &text); fs_give((void **) &tmp_file); return; } unlink(tmp_file); return; } /* otherwise we use /bin/spell */ sprintf(command, SPELL_COMMAND, (has_stop == TRUE) ? '+' : SPACECHAR, (has_stop == TRUE) ? SPELLSTOPFILE : EMPTYSTR, tmp_file); push_cursor(WATCH_CURSOR); sprintf(buffer,MLGetLocalized(XtNmsgExecuting,MsgExecuting),command); mm_log(buffer, NIL); if((fp = popen(command,"w")) != NULL) { (void) chmod(tmp_file,S_IRWXU); fwrite(text,strlen(text),1,fp); pclose(fp); } else { fs_give((void **) &text); fs_give((void **) &tmp_file); pop_cursor(); return; } if((fp = fopen(tmp_file,"r")) != NULL) { while((fgets(buffer,sizeof(buffer),fp)) != NULL) { buffer[strlen(buffer) - 1] = NUL_TERM; if(*buffer == NUL_TERM) continue; count ++; string_list = new_string_list(); string_list->string = cpystr(buffer); if(prev == NULL) base = string_list; else prev->next = string_list; prev = string_list; } fclose(fp); } else mm_log(MLGetLocalized(XtNmsgSpellNoRead,MsgSpellNoRead),NIL); fs_give((void **) &text); unlink(tmp_file); pop_cursor(); sprintf(buffer,MLGetLocalized(XtNmsgNCorrections,MsgNCorrections),count); mm_log(buffer, NIL); if(base) make_text_spell_window(compose->window->compose_text, base); return; } #ifdef __STDC__ void link_attachment(MLCompose *compose, PART *part, BODY *body, Binary_Buffer *binary_buffer) #else void link_attachment(compose,part,body,binary_buffer) MLCompose *compose; PART *part; BODY *body; Binary_Buffer *binary_buffer; #endif { Part_List *part_list; PART *current; BODY *subbody; Boolean attached = FALSE; add_attachment_contents_to_body(body,binary_buffer); /* * See if there is a selected attachment. Then check to see if * it is a multipart. If so, then we add to that multipart. */ if(compose->window->attach_list_selection && compose->part_list) { for(part_list = compose->part_list; part_list->partnumber != compose->window->attach_list_selection; part_list = part_list->next); subbody = &(part_list->part->body); if(subbody && subbody->type == TYPEMULTIPART) { current = subbody->contents.part; if(! current) subbody->contents.part = part; else { while(current->next) current = current->next; current->next = part; } attached = TRUE; } } /* * Wasn't a subpart, or we couldn't attach it as one. Attach to the * root part. */ if(! attached) { if(compose->attachments == NULL) { compose->attachments = part; } else { current = compose->attachments; while(current->next) current = current->next; current->next = part; } } make_attachment_list(compose, TRUE); return; } #ifdef __STDC__ void compose_parameters(Widget w, MLCompose *compose, XtPointer xp) #else void compose_parameters(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { Part_List *part_list; PARAMETER **old = NULL; PARAMETER *new = NULL; char *oldstr = NULL; char *newstr = NULL; /* See if there is a selected attachment. */ if(compose->window->attach_list_selection && compose->part_list) { for(part_list = compose->part_list; part_list->partnumber != compose->window->attach_list_selection; part_list = part_list->next) ; old = &part_list->part->body.parameter; } if(old == NULL) old = &compose->parameters; oldstr = param_to_str(*old); newstr = input_string(compose->window->shell, MLGetLocalized(XtNmsgPromptParams,MsgPromptParams), oldstr, PARAMSHELPFILE); if(newstr == NULL) return; if(*newstr == NUL_TERM) { fs_give((void **) &newstr); fs_give((void **) &oldstr); mail_free_body_parameter(old); } else { new = str_to_param(newstr); if(new != NULL) { mail_free_body_parameter(old); *old = new; } } fs_give((void **) &oldstr); fs_give((void **) &newstr); return; } /* * This is just to calculate how much space to allocate for storing * a text field. (Used in the print function). We over-allocate by * a little bit to make up for psuedo-tabs and line breaks. */ #ifdef __STDC__ unsigned long compose_field_approx_size(char *prefix, char *str, unsigned long len) #else unsigned long compose_field_approx_size(prefix, str, len) char *prefix; char *str; unsigned long len; #endif { unsigned long retval = 0L; if(!str) return(0L); if(len == 0L) return((unsigned long) strlen(str)); if(prefix) retval = strlen(prefix); retval += (unsigned long) strlen(str) + ((unsigned long) strlen(str) / len ) + (unsigned long) 16L; return(retval); } /* * This is an undocumented interface. * If you need it, you'll figure * it out. */ #ifdef __STDC__ void compose_smart_reply(ENVELOPE *env, char *newsgroups) #else void compose_smart_reply(env, newsgroups) ENVELOPE *env; char *newsgroups; #endif { FILE *fp; char *tmp_file; char mybuf[FILEBUFFLEN]; char filename[MAXPATHLEN]; char command[FILEBUFFLEN]; ADDRESS *curr; if(!preferences.smart_reply || *preferences.smart_reply == NUL_TERM) return; if(!strstr(preferences.smart_reply,"%s")) return; tmp_file = (char *) tmpnam(filename); sprintf(command,preferences.smart_reply,tmp_file); if((fp = fopen(tmp_file,"w")) != NULL) { (void) chmod(tmp_file,S_IRWXU); fprintf(fp,"%s ",HEADER_TO); for(curr = env->to; curr; curr = curr->next) { local_make_addr_str(curr,mybuf); fprintf(fp,"%s ",mybuf); } fprintf(fp,LFSTR); fprintf(fp,"%s ",HEADER_CC); for(curr = env->cc; curr; curr = curr->next) { local_make_addr_str(curr,mybuf); fprintf(fp,"%s ",mybuf); } fprintf(fp,LFSTR); fprintf(fp,"%s ",HEADER_BCC); for(curr = env->bcc; curr; curr = curr->next) { local_make_addr_str(curr,mybuf); fprintf(fp,"%s ",mybuf); } fprintf(fp,LFSTR); fprintf(fp,"%s %s\n", HEADER_NEWSGROUPS, (newsgroups) ? newsgroups : EMPTYSTR); fprintf(fp,"%s %s\n", HEADER_SUBJECT, (env->subject) ? env->subject : EMPTYSTR); fclose(fp); } /* * External process generates one line (or nothing). * If something, use it as the reply-to. */ *mybuf = NUL_TERM; if((fp = popen(command,"r")) != NULL) { fgets(mybuf,sizeof(mybuf),fp); mybuf[strlen(mybuf) - 1] = NUL_TERM; if(*mybuf != NUL_TERM) { mail_free_address(&env->reply_to); env->reply_to = text_to_address(mybuf,EMPTYSTR); } pclose(fp); } unlink(tmp_file); return; } #ifdef __STDC__ void compose_print(Widget w, MLCompose *compose, XtPointer xp) #else void compose_print(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { char *s; char *wrapped_text; unsigned long size = 0L; char *to = NULL; char *newsgroups = NULL; char *subject = NULL; char *cc = NULL; char *bcc = NULL; char *message_text = NULL; if(!preferences.print_command || *preferences.print_command == NUL_TERM) { mm_log(MLGetLocalized(XtNmsgNoPrintCommand,MsgNoPrintCommand),WARN); return; } push_cursor(WATCH_CURSOR); to = GetTextField(compose->window->to_text); newsgroups = GetTextField(compose->window->newsgroups_text); subject = GetTextField(compose->window->subject_text); cc = GetTextField(compose->window->cc_text); bcc = GetTextField(compose->window->bcc_text); message_text = GetTextField(compose->window->compose_text); s = fs_get( strlen(to) + strlen(newsgroups) + strlen(subject) + strlen(cc) + strlen(bcc) + strlen(message_text) + 1024); *s = NUL_TERM; #define HEADER_MARGIN (COMPOSEWIDTH - 20) if(*to != NUL_TERM) { strcat(s,MLGetLocalized(XtNheaderTo,HeaderTo)); strcat(s,TABSTR); wrapped_text = wrap_text(to, HEADER_MARGIN); strcat(s, wrapped_text); strcat(s, LFSTR); } if(*newsgroups != NUL_TERM) { strcat(s,MLGetLocalized(XtNheaderNewsgroups,HeaderNewsgroups)); strcat(s,TABSTR); wrapped_text = wrap_text(newsgroups, HEADER_MARGIN); strcat(s, wrapped_text); strcat(s, LFSTR); } if(*subject != NUL_TERM) { strcat(s,MLGetLocalized(XtNheaderSubject,HeaderSubject)); strcat(s,TABSTR); wrapped_text = wrap_text(subject, HEADER_MARGIN); strcat(s, wrapped_text); strcat(s, LFSTR); } if(*cc != NUL_TERM) { strcat(s,MLGetLocalized(XtNheaderCc,HeaderCc)); strcat(s,TABSTR); wrapped_text = wrap_text(cc, HEADER_MARGIN); strcat(s, wrapped_text); strcat(s, LFSTR); } if(*bcc != NUL_TERM) { strcat(s,MLGetLocalized(XtNheaderBcc,HeaderBcc)); strcat(s,TABSTR); wrapped_text = wrap_text(bcc, HEADER_MARGIN); strcat(s, wrapped_text); strcat(s, LFSTR); } strcat(s, LFSTR); if(*message_text != NUL_TERM) { wrapped_text = wrap_text(message_text, COMPOSEWIDTH - 1); strcat(s, wrapped_text); strcat(s, LFSTR); } if((write_to_pipe(preferences.print_command, NULL,s,strlen(s))) != SYSCALL_SUCCESS) mm_log(MLGetLocalized(XtNmsgPrintFail,MsgPrintFail), WARN); else mm_log(MLGetLocalized(XtNmsgPrintSuccess,MsgPrintSuccess), NIL); fs_give((void **) &s); fs_give((void **) &to); fs_give((void **) &newsgroups); fs_give((void **) &subject); fs_give((void **) &cc); fs_give((void **) &bcc); fs_give((void **) &message_text); pop_cursor(); return; } #ifdef __STDC__ void compose_mailbox_close(MAILSTREAM *mailstream) #else void compose_mailbox_close(mailstream) MAILSTREAM *mailstream; #endif { MLCompose *compose; if(session->compose == NULL) return; /* * Run through the list of compose sessions searching for our mailstream. * If it's ours, zero the message structure so it won't be referenced again. * (The message can still be composed -- we just won't set any flags at * the end). */ for(compose = session->compose ; compose; compose = compose->next) { if((compose->message != NULL) && (compose->message->mailstream == mailstream)) { compose->message = NULL; } } } #ifdef __STDC__ void compose_options(Widget w, MLCompose *compose, XtPointer xp) #else void compose_options(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { compose_preferences(compose); return; } Menu copts_menu[] = { { NULL, "accept", NUL_TERM, cwin_accept, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "save", NUL_TERM, cwin_save, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "dismiss", NUL_TERM, cwin_dismiss, NULL, 0, NULL, NULL, BTN_ON }, { NULL, "HELP", NUL_TERM, cwin_help, NULL, 0, NULL, NULL, BTN_ON }, }; #ifdef __STDC__ void compose_preferences(MLCompose *compose) #else void compose_preferences(compose) MLCompose *compose; #endif { Arg args[ARGLISTSIZE]; int n = 0; MLComposeOptions *options; MLComposeOptionsWindow *win; if(compose->options->window != NULL) { win = compose->options->window; if(win->destroyed == FALSE) { if(win->is_realized == TRUE) de_iconify(win->shell); else XtPopup(win->shell, XtGrabNone); return; } } options = compose->options; options->window = (MLComposeOptionsWindow *) fs_get(sizeof(MLComposeOptionsWindow)); win = options->window; win->buttonlist = NULL; win->destroyed = FALSE; win->is_realized = FALSE; if(preferences.autoPlace == TRUE) { XtSetArg(args[n], XtNx, -1000); n ++; XtSetArg(args[n], XtNy, -1000); n ++; } XtSetArg (args[n], XmNdeleteResponse, XmDO_NOTHING); n++; win->shell = XtCreatePopupShell("composeOptions", topLevelShellWidgetClass, compose->window->shell, args, n); AddDestroyCallback (win->shell); n = 0; setup_editres(win->shell); if(ml_icon != (Pixmap) None) XtVaSetValues(win->shell, XmNiconPixmap,ml_icon, NULL); win->form = XmCreateForm(win->shell, "form", args, n ); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n ++; win->menubar = XmCreateMenuBar(win->form, "menubar", args, n); n = 0; XtManageChild(win->menubar); make_buttons(&win->buttonlist, NULL, win->menubar, copts_menu, XtNumber(copts_menu), BTN_ON, (XtPointer) compose, ROOTMENULEVEL); win->mailhost = create_text_field(win->form, win->menubar, "mailhost", options->mailhost, 0, NULL, NULL); win->nntphost = create_text_field(win->form, win->mailhost, "nntphost", options->nntphost, 0, NULL, NULL); win->domain = create_text_field(win->form, win->nntphost, "domain", options->domain, 0, NULL, NULL); win->replyto = create_text_field(win->form, win->domain, "replyto", options->replyto, 0, NULL, NULL); win->sigfile = create_text_field(win->form, win->replyto, "sigfile", options->sigfile, 0, NULL, NULL); win->outlog = create_text_field(win->form, win->sigfile, "outlog", options->outlog, 0, NULL, NULL); win->defcc = create_text_field(win->form, win->outlog, "defcc", options->defcc, 0, NULL, NULL); win->defbcc = create_text_field(win->form, win->defcc, "defbcc", options->defbcc, 0, NULL, NULL); win->charset = create_text_field(win->form, win->defbcc, "charset", options->charset, 0, NULL, NULL); win->language = create_text_field(win->form, win->charset, "language", options->language, 0, NULL, NULL); XtSetArg(args[n], XmNadjustMargin, FALSE); n ++; XtSetArg(args[n], XmNmarginWidth, 0); n ++; XtSetArg(args[n], XmNborderWidth, 0); n ++; XtSetArg(args[n], XmNnumColumns, 3); n ++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n ++; XtSetArg(args[n], XmNtopWidget, win->language); n ++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n ++; XtSetArg(args[n], XmNorientation, XmVERTICAL); n ++; XtSetArg(args[n], XmNpacking, XmPACK_COLUMN); n ++; win->rowcol = XtCreateWidget("rowcol", xmRowColumnWidgetClass, win->form, args, n ); n = 0; XtManageChild(win->rowcol); XtSetArg(args[n], XmNborderWidth, 0); n ++; XtSetArg(args[n], XmNtraversalOn, FALSE); n ++; win->verbose = XmCreateToggleButton(win->rowcol, "verbose_toggle", args, n); n = 0; XtManageChild(win->verbose); XtAddCallback(win->verbose, XmNvalueChangedCallback, (XtCallbackProc) cwin_verbose, compose); XtSetArg(args[n], XmNborderWidth, 0); n ++; XtSetArg(args[n], XmNtraversalOn, FALSE); n ++; win->keep_open = XmCreateToggleButton(win->rowcol, "keep_open_toggle", args, n); n = 0; XtManageChild(win->keep_open); XtAddCallback(win->keep_open, XmNvalueChangedCallback, (XtCallbackProc) cwin_keep_open, compose); XtSetArg(args[n], XmNborderWidth, 0); n ++; XtSetArg(args[n], XmNtraversalOn, FALSE); n ++; win->send_eight = XmCreateToggleButton(win->rowcol, "send_eight_toggle", args, n); n = 0; XtManageChild(win->send_eight); XtAddCallback(win->send_eight, XmNvalueChangedCallback, (XtCallbackProc) cwin_send_eight, compose); XtSetArg(args[n], XmNborderWidth, 0); n ++; XtSetArg(args[n], XmNtraversalOn, FALSE); n ++; win->word_wrap = XmCreateToggleButton(win->rowcol, "word_wrap_toggle", args, n); n = 0; XtManageChild(win->word_wrap); XtAddCallback(win->word_wrap, XmNvalueChangedCallback, (XtCallbackProc) cwin_word_wrap, compose); XtSetArg(args[n], XmNborderWidth, 0); n ++; XtSetArg(args[n], XmNtraversalOn, FALSE); n ++; win->message_log = XmCreateToggleButton(win->rowcol, "message_log_toggle", args, n); n = 0; XtManageChild(win->message_log); XtAddCallback(win->message_log, XmNvalueChangedCallback, (XtCallbackProc) cwin_message_log, compose); XtSetArg(args[n], XmNborderWidth, 0); n ++; XtSetArg(args[n], XmNtraversalOn, FALSE); n ++; win->log_attachments = XmCreateToggleButton(win->rowcol, "log_attachments_toggle", args, n); n = 0; XtManageChild(win->log_attachments); XtAddCallback(win->log_attachments, XmNvalueChangedCallback, (XtCallbackProc) cwin_log_attachments, compose); XtAddCallback(win->shell, XmNpopdownCallback, (XtCallbackProc) cwin_popdown, compose); XtAddCallback(win->shell, XmNdestroyCallback, (XtCallbackProc) cwin_destroy, compose); set_initial_buttons(compose); XtManageChild(win->form); XtManageChild(win->shell); XtPopup(win->shell, XtGrabNone); position_popup_widget(win->shell, FALSE); win->is_realized = TRUE; return; } #ifdef __STDC__ void cwin_help(Widget w, MLCompose *compose, XtPointer xp) #else void cwin_help(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { help(compose->options->window->shell,COPTHELPFILE); return; } #ifdef __STDC__ void set_initial_buttons(MLCompose *compose) #else void set_initial_buttons(compose) MLCompose *compose; #endif { MLComposeOptions *options = compose->options; MLComposeOptionsWindow *win = compose->options->window; XmToggleButtonSetState(win->verbose,options->verbose,FALSE); XmToggleButtonSetState(win->keep_open,options->keep_open,FALSE); XmToggleButtonSetState(win->send_eight,options->send_eight,FALSE); XmToggleButtonSetState(win->word_wrap,options->word_wrap,FALSE); XmToggleButtonSetState(win->message_log,options->message_log,FALSE); XmToggleButtonSetState(win->log_attachments,options->log_attachments,FALSE); return; } #ifdef __STDC__ void cwin_accept(Widget w, MLCompose *compose, XtPointer xp) #else void cwin_accept(w, compose, xp) Widget w; MLCompose *compose; XtPointer xp; #endif { get_compose_options(compose); cwin_dismiss(w,compose,xp); return; } #ifdef __STDC__ void cwin_save(Widget w, MLCompose *compose, XtPointer xp) #else void cwin_save(w, compose, xp) Widget w; MLCompose *compose; XtPointer xp; #endif { MLComposeOptions *options = compose->options; get_compose_options(compose); fs_give((void **) &preferences.smtp_server); preferences.smtp_server = cpystr(options->mailhost); fs_give((void **) &preferences.nntp_server); preferences.nntp_server = cpystr(options->nntphost); fs_give((void **) &preferences.default_domain); preferences.default_domain = cpystr(options->domain); fs_give((void **) &preferences.reply_address); preferences.reply_address = cpystr(options->replyto); fs_give((void **) &preferences.charset); preferences.charset = cpystr(options->charset); fs_give((void **) &preferences.signature_file); preferences.signature_file = cpystr(options->sigfile); fs_give((void **) &preferences.language); preferences.language = cpystr(options->language); fs_give((void **) &preferences.sendlog); preferences.sendlog = cpystr(options->outlog); fs_give((void **) &preferences.default_cc); preferences.default_cc = cpystr(options->defcc); fs_give((void **) &preferences.default_bcc); preferences.default_bcc = cpystr(options->defbcc); preferences.smtp_debug = options->verbose; preferences.keep_open = options->keep_open; preferences.send_eight = options->send_eight; preferences.word_wrap = options->word_wrap; preferences.logit = options->message_log; preferences.log_full = options->log_attachments; save_defaults(); cwin_dismiss(w,compose,xp); } #ifdef __STDC__ void cwin_dismiss(Widget w, MLCompose *compose, XtPointer xp) #else void cwin_dismiss(w, compose, xp) Widget w; MLCompose *compose; XtPointer xp; #endif { XtPopdown(compose->options->window->shell); compose->options->window->is_realized = FALSE; return; } #ifdef __STDC__ void cwin_popdown(Widget w, MLCompose *compose, XtPointer xp) #else void cwin_popdown(w, compose, xp) Widget w; MLCompose *compose; XtPointer xp; #endif { compose->options->window->is_realized = FALSE; return; } #ifdef __STDC__ void cwin_destroy(Widget w, MLCompose *compose, XtPointer xp) #else void cwin_destroy(w, compose, xp) Widget w; MLCompose *compose; XtPointer xp; #endif { compose->options->window->is_realized = FALSE; compose->options->window->destroyed = TRUE; fs_give((void **) &compose->options->window->buttonlist); return; } #ifdef __STDC__ void get_compose_options(MLCompose *compose) #else void get_compose_options(compose) MLCompose *compose; #endif { MLComposeOptions *options = compose->options; fs_give((void **) &options->mailhost); options->mailhost = GetTextField(options->window->mailhost); fs_give((void **) &options->nntphost); options->nntphost = GetTextField(options->window->nntphost); fs_give((void **) &options->domain); options->domain = GetTextField(options->window->domain); fs_give((void **) &options->replyto); options->replyto = GetTextField(options->window->replyto); fs_give((void **) &options->sigfile); options->sigfile = GetTextField(options->window->sigfile); fs_give((void **) &options->charset); options->charset = GetTextField(options->window->charset); fs_give((void **) &options->language); options->language = GetTextField(options->window->language); fs_give((void **) &options->outlog); options->outlog = GetTextField(options->window->outlog); fs_give((void **) &options->defcc); options->defcc = GetTextField(options->window->defcc); fs_give((void **) &options->defbcc); options->defbcc = GetTextField(options->window->defbcc); if(options->word_wrap != options->word_wrap_tmp) if(options->word_wrap_tmp == TRUE) compose_wrap_on(NULL,compose,NULL); else compose_wrap_off(NULL,compose,NULL); options->verbose = options->verbose_tmp; options->keep_open = options->keep_open_tmp; options->send_eight = options->send_eight_tmp; options->word_wrap = options->word_wrap_tmp; options->message_log = options->message_log_tmp; options->log_attachments = options->log_attachments_tmp; return; } #ifdef __STDC__ void cwin_verbose(Widget w,MLCompose *compose, XmToggleButtonCallbackStruct *xp) #else void cwin_verbose(w,compose,xp) Widget w; MLCompose *compose; XmToggleButtonCallbackStruct *xp; #endif { MLComposeOptions *options = compose->options; if(xp->set == TRUE) options->verbose_tmp = TRUE; else options->verbose_tmp = FALSE; return; } #ifdef __STDC__ void cwin_keep_open(Widget w,MLCompose *compose, XmToggleButtonCallbackStruct *xp) #else void cwin_keep_open(w,compose,xp) Widget w; MLCompose *compose; XmToggleButtonCallbackStruct *xp; #endif { MLComposeOptions *options = compose->options; if(xp->set == TRUE) options->keep_open_tmp = TRUE; else options->keep_open_tmp = FALSE; return; } #ifdef __STDC__ void cwin_send_eight(Widget w,MLCompose *compose, XmToggleButtonCallbackStruct *xp) #else void cwin_send_eight(w,compose,xp) Widget w; MLCompose *compose; XmToggleButtonCallbackStruct *xp; #endif { MLComposeOptions *options = compose->options; if(xp->set == TRUE) options->send_eight_tmp = TRUE; else options->send_eight_tmp = FALSE; return; } #ifdef __STDC__ void cwin_word_wrap(Widget w,MLCompose *compose, XmToggleButtonCallbackStruct *xp) #else void cwin_word_wrap(w,compose,xp) Widget w; MLCompose *compose; XmToggleButtonCallbackStruct *xp; #endif { MLComposeOptions *options = compose->options; if(xp->set == TRUE) options->word_wrap_tmp = TRUE; else options->word_wrap_tmp = FALSE; return; } #ifdef __STDC__ void cwin_message_log(Widget w,MLCompose *compose, XmToggleButtonCallbackStruct *xp) #else void cwin_message_log(w,compose,xp) Widget w; MLCompose *compose; XmToggleButtonCallbackStruct *xp; #endif { MLComposeOptions *options = compose->options; if(xp->set == TRUE) options->message_log_tmp = TRUE; else options->message_log_tmp = FALSE; return; } #ifdef __STDC__ void cwin_log_attachments(Widget w,MLCompose *compose, XmToggleButtonCallbackStruct *xp) #else void cwin_log_attachments(w,compose,xp) Widget w; MLCompose *compose; XmToggleButtonCallbackStruct *xp; #endif { MLComposeOptions *options = compose->options; if(xp->set == TRUE) options->log_attachments_tmp = TRUE; else options->log_attachments_tmp = FALSE; return; } #ifdef __STDC__ void compose_reply_insert(Widget w, MLCompose *compose, XtPointer xp) #else void compose_reply_insert(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { Read *read; XmTextPosition left, right; char *the_text = NULL; char *tmp; Boolean found = FALSE; char buffer[FILEBUFFLEN]; push_cursor(WATCH_CURSOR); for(read = session->read; read != NULL; read = read->next) { if(read->is_realized == TRUE) { XmTextGetSelectionPosition(read->read_text,&left,&right); if(left != right) { tmp = XmTextGetSelection(read->read_text); the_text = copywrap(tmp, (COMPOSEWIDTH - 2) - strlen(preferences.reply_prefix)); fs_give((void **) &tmp); found = TRUE; } } } if(! found) { if(compose->reply_text) { /* add the attribution and original message to the reply body */ memset(buffer, 0, FILEBUFFLEN); make_attribution_line(compose->message,buffer); if(*buffer) { strcat(buffer,"\n"); text_blast(compose->window->compose_text, copywrap(buffer,COMPOSEWIDTH)); } the_text = copywrap(compose->reply_text, (COMPOSEWIDTH - 2) - strlen(preferences.reply_prefix)); found ++; } } if((found) && (*the_text != NUL_TERM)) { tmp = add_prefix(the_text); left = XmTextGetInsertionPosition(compose->window->compose_text); right = left + strlen(tmp); text_blast(compose->window->compose_text,tmp); fs_give((void **) &tmp); } if(the_text) fs_give((void **) &the_text); pop_cursor(); return; } #ifdef __STDC__ void compose_cut(Widget w, MLCompose *compose, XtPointer xp) #else void compose_cut(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { XmTextCut(compose->window->compose_text, XtLastTimestampProcessed(display)); return; } #ifdef __STDC__ void compose_copy(Widget w, MLCompose *compose, XtPointer xp) #else void compose_copy(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { XmTextCopy(compose->window->compose_text, XtLastTimestampProcessed(display)); return; } #ifdef __STDC__ void compose_paste(Widget w, MLCompose *compose, XtPointer xp) #else void compose_paste(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { XmTextPaste(compose->window->compose_text); return; } #ifdef __STDC__ void compose_save_draft(Widget w, MLCompose *compose, XtPointer xp) #else void compose_save_draft(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { FILE *fp; char *filename; Boolean append_it; char *tmp; filename = file_select(compose->window->shell, NULL, DRAFT_FILEPAT, DRAFT_TEXT, TRUE, &append_it); if(filename == NULL) return; push_cursor(WATCH_CURSOR); if((fp = fopen(filename,(append_it == TRUE) ? "a" : "w")) != NULL) { (void) chmod(filename,S_IRWXU); fprintf(fp,"%s\n",ML_DRAFT_HEADER); fprintf(fp,"%s\t%s\n",HEADER_FROM,compose->options->replyto); tmp = XmTextGetString(compose->window->to_text); if(*tmp) fprintf(fp,"%s\t%s\n",HEADER_TO,tmp); fs_give((void **) &tmp); tmp = XmTextGetString(compose->window->newsgroups_text); if(*tmp) fprintf(fp,"%s\t%s\n",HEADER_NEWSGROUPS,tmp); fs_give((void **) &tmp); tmp = XmTextGetString(compose->window->subject_text); if(*tmp) fprintf(fp,"%s\t%s\n",HEADER_SUBJECT,tmp); fs_give((void **) &tmp); tmp = XmTextGetString(compose->window->cc_text); if(*tmp) fprintf(fp,"%s\t%s\n",HEADER_CC,tmp); fs_give((void **) &tmp); tmp = XmTextGetString(compose->window->bcc_text); if(*tmp) fprintf(fp,"%s\t%s\n",HEADER_BCC,tmp); fs_give((void **) &tmp); fprintf(fp,"\n"); tmp = XmTextGetString(compose->window->compose_text); fprintf(fp,"%s",tmp); fs_give((void **) &tmp); fclose(fp); } fs_give((void **) &filename); pop_cursor(); return; } #ifdef __STDC__ void compose_load_draft(Widget w, MLCompose *compose, XtPointer xp) #else void compose_load_draft(w,compose,xp) Widget w; MLCompose *compose; XtPointer xp; #endif { FILE *fp; char *filename; char buffer[2 * FILEBUFFLEN]; struct stat st; int c; char *str; char *dst; filename = file_select(compose->window->shell, NULL, DRAFT_FILEPAT, DRAFT_TEXT, FALSE, NULL); if(filename == NULL) return; if(stat(filename,&st) != SYSCALL_SUCCESS) { fs_give((void **) &filename); return; } if((fp = fopen(filename,"r")) != NULL) { fgets(buffer,sizeof(buffer),fp); buffer[strlen(buffer) - 1] = NUL_TERM; if(strcmp(buffer,ML_DRAFT_HEADER) != STRMATCH) { fs_give((void **) &filename); mm_log(MLGetLocalized(XtNmsgNotDraft,MsgNotDraft),ERROR); return; } push_cursor(WATCH_CURSOR); XtVaSetValues(compose->window->shell, XmNtitle, MLGetLocalized(XtNstrDraft,StrDraft), NULL); while(fgets(buffer,sizeof(buffer),fp) != NULL) { buffer[strlen(buffer) - 1] = NUL_TERM; if(! strlen(buffer)) break; if(strncmp(buffer,HEADER_FROM,strlen(HEADER_FROM)) == STRMATCH) { fs_give((void **) &compose->options->replyto); compose->options->replyto = cpystr(buffer + strlen(HEADER_FROM) + 1); } if(strncmp(buffer,HEADER_TO,strlen(HEADER_TO)) == STRMATCH) AppendText(compose->window->to_text,buffer + strlen(HEADER_TO) + 1); if(strncmp(buffer,HEADER_NEWSGROUPS, strlen(HEADER_NEWSGROUPS)) == STRMATCH) AppendText(compose->window->newsgroups_text, buffer + strlen(HEADER_NEWSGROUPS) + 1); if(strncmp(buffer,HEADER_SUBJECT,strlen(HEADER_SUBJECT)) == STRMATCH) AppendText(compose->window->subject_text, buffer + strlen(HEADER_SUBJECT) + 1); if(strncmp(buffer,HEADER_CC,strlen(HEADER_CC)) == STRMATCH) AppendText(compose->window->cc_text,buffer + strlen(HEADER_CC) + 1); if(strncmp(buffer,HEADER_BCC,strlen(HEADER_BCC)) == STRMATCH) AppendText(compose->window->bcc_text,buffer + strlen(HEADER_BCC) + 1); } str = (char *) fs_get(st.st_size + 1); dst = str; while((c = fgetc(fp)) != EOF) { *dst = c; dst ++; } *dst = NUL_TERM; fclose(fp); AppendText(compose->window->compose_text,str); fs_give((void **) &str); } fs_give((void **) &filename); pop_cursor(); return; } #ifdef __STDC__ void compose_pop(Widget w, XtPointer xp) #else void compose_pop(w,xp) Widget w; XtPointer xp; #endif { MLCompose *compose; for(compose = session->compose; compose; compose = compose->next) { if(compose->window->compose_text == w) { compose_destroy_current(w,compose,NULL); break; } } return; }