/*---------------------------------------------------------------------- Offer to delete old sent-mail folders Args: sml -- The list of sent-mail folders fcc_cntxt -- context to delete list of folders in type -- label indicating type of folders being deleted ----*/ void delete_old_mail(struct sm_folder *sml, CONTEXT_S *fcc_cntxt, char *type) { char prompt[150]; struct sm_folder *sm; for(sm = sml; sm != NULL && sm->name != NULL; sm++){ if(sm->name[0] == '\0') /* can't happen */ continue; snprintf(prompt, sizeof(prompt), "To save disk space, delete old%.10s mail folder \"%.30s\" ", type, sm->name); if(want_to(prompt, 'n', 0, h_wt_delete_old, WT_FLUSH_IN) == 'y'){ if(!context_delete(fcc_cntxt, NULL, sm->name)){ q_status_message1(SM_ORDER, 3, 3, "Error deleting \"%s\".", sm->name); dprint((1, "Error context_deleting %s in %s\n", sm->name, (fcc_cntxt && fcc_cntxt->context) ? fcc_cntxt->context : "<null>")); } else{ int index; if((index = folder_index(sm->name, fcc_cntxt, FI_FOLDER)) >= 0) folder_delete(index, FOLDERS(fcc_cntxt)); } }else{ /* break;*/ /* skip out of the whole thing when he says no */ /* Decided to keep asking anyway */ } } }
/*---------------------------------------------------------------------- Send a line of text to the printer Args: line -- Text to print ----*/ void print_text(char *line) { #ifndef _WINDOWS int slen = strlen(line); while(!ps_global->print->err && slen--) if(print_char(*line++) == 0) ps_global->print->err = 1; #else /* _WINDOWS */ if(!ps_global->print->err && (ps_global->print->err = mswin_print_text_utf8(line))) q_status_message1(SM_ORDER, 0, 9, "Print cancelled: %s", mswin_print_error((unsigned short)ps_global->print->err)); #endif /* _WINDOWS */ }
int rfc2231_list_params(PARMLIST_S *plist) { PARAMETER *pp, **ppp; int i; if(plist->value) fs_give((void **) &plist->value); for(pp = plist->list; pp; pp = pp->next){ /* get a name */ for(i = 0; i < 32; i++) if(!(plist->attrib[i] = pp->attribute[i]) || pp->attribute[i] == '*'){ plist->attrib[i] = '\0'; for(ppp = &plist->seen; *ppp && strucmp((*ppp)->attribute, plist->attrib); ppp = &(*ppp)->next) ; if(!*ppp){ plist->list = pp->next; *ppp = mail_newbody_parameter(); /* add to seen list */ (*ppp)->attribute = cpystr(plist->attrib); plist->value = parameter_val(pp,plist->attrib); return(TRUE); } break; } if(i >= 32) q_status_message1(SM_ORDER | SM_DING, 0, 3, "Overly long attachment parameter ignored: %.25s...", pp->attribute); } return(FALSE); }
/*---------------------------------------------------------------------- Print a single character, translate from UTF-8 to user's locale charset. Args: c -- char to print Returns: 1 on success, 0 on ps_global->print->err ----*/ int print_char(int c) { #ifndef _WINDOWS int i, outchars; unsigned char obuf[MAX(MB_LEN_MAX,32)]; if(!ps_global->print->err && (outchars = utf8_to_locale(c, &cb, obuf, sizeof(obuf)))){ for(i = 0; i < outchars && !ps_global->print->err; i++) if(putc(obuf[i], ps_global->print->fp) == EOF) ps_global->print->err = 1; } #else /* _WINDOWS */ if(!ps_global->print->err && (ps_global->print->err = mswin_print_char_utf8(c))) q_status_message1(SM_ORDER, 0, 9, "Print cancelled: %s", mswin_print_error((unsigned short)ps_global->print->err)); #endif /* _WINDOWS */ return(!ps_global->print->err); }
/*---------------------------------------------------------------------- handle hang up signal -- SIGUSR2 Not much to do. Rely on periodic mail file check pointing. ----------------------------------------------------------------------*/ static RETSIGTYPE usr2_signal(int sig) { char c, *mbox, mboxbuf[20]; int i; MAILSTREAM *stream; NETMBX mb; for(i = 0; i < ps_global->s_pool.nstream; i++) { stream = ps_global->s_pool.streams[i]; if(stream && sp_flagged(stream, SP_LOCKED) && !sp_dead_stream(stream) && !stream->lock && !stream->rdonly && stream->mailbox && (c = *stream->mailbox) != '{' && c != '*') { pine_mail_check(stream); /* write latest state */ stream->rdonly = 1; /* and become read-only */ (void) pine_mail_ping(stream); mbox = stream->mailbox; if(!strucmp(stream->mailbox, ps_global->inbox_name) || !strcmp(stream->mailbox, ps_global->VAR_INBOX_PATH) || !strucmp(stream->original_mailbox, ps_global->inbox_name) || !strcmp(stream->original_mailbox, ps_global->VAR_INBOX_PATH)) mbox = "INBOX"; else if(mail_valid_net_parse(stream->mailbox, &mb) && mb.mailbox) mbox = mb.mailbox; q_status_message1(SM_ASYNC, 3, 7, _("Another email program is accessing %s. Session now Read-Only."), short_str((mbox && *mbox) ? mbox : "folder", mboxbuf, sizeof(mboxbuf), 19, FrontDots)); dprint((1, "** folder %s went read-only **\n\n", stream->mailbox)); } } }
char * rfc2231_get_param(PARAMETER *parms, char *name, char **charset, char **lang) { char *buf, *p; int decode = 0, name_len, i; unsigned n; name_len = strlen(name); for(; parms ; parms = parms->next) if(!struncmp(name, parms->attribute, name_len)){ if(parms->attribute[name_len] == '*'){ for(p = &parms->attribute[name_len + 1], n = 0; *(p+n); n++) ; decode = *(p + n - 1) == '*'; if(isdigit((unsigned char) *p)){ char *pieces[RFC2231_MAX]; int count = 0, len; memset(pieces, 0, RFC2231_MAX * sizeof(char *)); while(parms){ n = 0; do n = (n * 10) + (*p - '0'); while(isdigit(*++p) && n < RFC2231_MAX); if(n < RFC2231_MAX){ pieces[n] = parms->value; if(n > count) count = n; } else{ q_status_message1(SM_ORDER | SM_DING, 0, 3, "Invalid attachment parameter segment number: %.25s", name); return(NULL); /* Too many segments! */ } while((parms = parms->next) != NULL) if(!struncmp(name, parms->attribute, name_len)){ if(*(p = &parms->attribute[name_len]) == '*' && isdigit((unsigned char) *++p)) break; else return(NULL); /* missing segment no.! */ } } for(i = len = 0; i <= count; i++) if(pieces[i]) len += strlen(pieces[i]); else{ q_status_message1(SM_ORDER | SM_DING, 0, 3, "Missing attachment parameter sequence: %.25s", name); return(NULL); /* hole! */ } buf = (char *) fs_get((len + 1) * sizeof(char)); for(i = len = 0; i <= count; i++){ if((n = *(p = pieces[i]) == '\"') != 0) /* quoted? */ p++; while(*p && !(n && *p == '\"' && !*(p+1))) buf[len++] = *p++; } buf[len] = '\0'; } else buf = cpystr(parms->value); /* Do any RFC 2231 decoding? */ if(decode){ char *converted = NULL, cs[1000]; cs[0] = '\0'; n = 0; if((p = strchr(buf, '\'')) != NULL){ n = (p - buf) + 1; *p = '\0'; strncpy(cs, buf, sizeof(cs)); cs[sizeof(cs)-1] = '\0'; *p = '\''; if(charset) *charset = cpystr(cs); if((p = strchr(&buf[n], '\'')) != NULL){ n = (p - buf) + 1; if(lang){ *p = '\0'; *lang = cpystr(p); *p = '\''; } } } if(n){ /* Suck out the charset & lang while decoding hex */ p = &buf[n]; for(i = 0; (buf[i] = *p) != '\0'; i++) if(*p++ == '%' && isxpair(p)){ buf[i] = X2C(p); p += 2; } } else fs_give((void **) &buf); /* problems!?! */ /* * Callers will expect the returned value to be UTF-8 * text, so we may need to translate here. */ if(buf) converted = convert_to_utf8(buf, cs, 0); if(converted && converted != buf){ fs_give((void **) &buf); buf = converted; } } return(buf); } else return(cpystr(parms->value ? parms->value : "")); } return(NULL); }
int rd_prompt_about_forged_remote_data(int reason, REMDATA_S *rd, char *extra) { char tmp[2000]; char *unknown = "<unknown>"; int rv = -1; char *foldertype, *foldername, *special; foldertype = (rd && rd->t.i.special_hdr && !strucmp(rd->t.i.special_hdr, REMOTE_ABOOK_SUBTYPE)) ? "address book" : (rd && rd->t.i.special_hdr && !strucmp(rd->t.i.special_hdr, REMOTE_PINERC_SUBTYPE)) ? "configuration" : "data"; foldername = (rd && rd->rn) ? rd->rn : unknown; special = (rd && rd->t.i.special_hdr) ? rd->t.i.special_hdr : unknown; dprint((1, "rd_check_out_forged_remote_data:\n")); dprint((1, " reason=%d\n", reason)); dprint((1, " folder_type=%s\n", foldertype ? foldertype : "?")); dprint((1, " remotename=%s\n\n", foldername ? foldername : "?")); if(rd && rd->flags & USER_SAID_NO) return rv; if(reason == -2){ dprint((1, "The special header \"%s\" is missing from the last message in the folder.\nThis indicates that something is wrong.\nYou should probably answer \"No\"\nso that you don't use the corrupt data.\nThen you should investigate further.\n", special ? special : "?")); } else if(reason == -1){ dprint((1, "The last message in the folder contains \"Received\" headers.\nThis usually indicates that the message was put there by the mail\ndelivery system. Alpine does not add those Received headers.\nYou should probably answer \"No\" so that you don't use the corrupt data.\nThen you should investigate further.\n")); } else if(reason == 0){ dprint((1, "The special header \"%s\" in the last message\nin the folder has an unexpected value (%s)\nafter it. This could indicate that something is wrong.\nThis value should not normally be put there by Alpine.\nHowever, since there are no Received lines in the message we choose to\nbelieve that everything is ok and we will proceed.\n", special ? special : "?", (extra && *extra) ? extra : "?")); } else if(reason == 1){ dprint((1, "The special header \"%s\" in the last message\nin the folder has an unexpected value (1)\nafter it. It appears that it may have been put there by an Pine\nwith a version number less than 4.50.\nSince there are no Received lines in the message we choose to believe that\nthe header was added by an old Pine and we will proceed.\n", special ? special : "?")); } else if(reason > 1){ dprint((1, "The special header \"%s\" in the last message\nin the folder has an unexpected value (%s)\nafter it. This is the right sort of value that Alpine would normally put there,\nbut it doesn't match the value from the first message in the folder.\nThis may indicate that something is wrong.\nHowever, since there are no Received lines in the message we choose to\nbelieve that everything is ok and we will proceed.\n", special ? special : "?", (extra && *extra) ? extra : "?")); } if(reason >= 0){ /* * This check should not really be here. We have a cookie that * has the wrong value so something is possibly wrong. * But we are worried that old pines will put the bad value in * there (which they will) and then the questions will bother * users and mystify them. So we're just going to pretend the user * said Yes in this case, and we'll try to fix the cookie. * We still catch Received lines and use that or the complete absence * of a special header as indicators of trouble. */ rd->flags |= USER_SAID_YES; return(1); } if(ps_global->ttyo){ SCROLL_S sargs; STORE_S *in_store, *out_store; gf_io_t pc, gc; HANDLE_S *handles = NULL; int the_answer = 'n'; if(!(in_store = so_get(CharStar, NULL, EDIT_ACCESS)) || !(out_store = so_get(CharStar, NULL, EDIT_ACCESS))) goto try_wantto; /* TRANSLATORS: the first %s is the folder type, it may be address book or configuration. The second %s is the folder name. Of course, the HTML tags should be left as is. */ snprintf(tmp, sizeof(tmp), _("<HTML><P>The data in the remote %s folder<P><CENTER>%s</CENTER><P>looks suspicious. The reason for the suspicion is<P><CENTER>"), foldertype, foldername); tmp[sizeof(tmp)-1] = '\0'; so_puts(in_store, tmp); if(reason == -2){ snprintf(tmp, sizeof(tmp), _("header \"%s\" is missing</CENTER><P>The special header \"%s\" is missing from the last message in the folder. This indicates that something is wrong. You should probably answer \"No\" so that you don't use the corrupt data. Then you should investigate further."), special, special); tmp[sizeof(tmp)-1] = '\0'; so_puts(in_store, tmp); } else if(reason == -1){ so_puts(in_store, _("\"Received\" headers detected</CENTER><P>The last message in the folder contains \"Received\" headers. This usually indicates that the message was put there by the mail delivery system. Alpine does not add those Received headers. You should probably answer \"No\" so that you don't use the corrupt data. Then you should investigate further.")); } else if(reason == 0){ snprintf(tmp, sizeof(tmp), _("Unexpected value for header \"%s\"</CENTER><P>The special header \"%s\" in the last message in the folder has an unexpected value (%s) after it. This probably indicates that something is wrong. This value would not normally be put there by Alpine. You should probably answer \"No\" so that you don't use the corrupt data. Then you should investigate further."), special, special, (extra && *extra) ? extra : "?"); tmp[sizeof(tmp)-1] = '\0'; so_puts(in_store, tmp); } else if(reason == 1){ snprintf(tmp, sizeof(tmp), _("Unexpected value for header \"%s\"</CENTER><P>The special header \"%s\" in the last message in the folder has an unexpected value (1) after it. It appears that it may have been put there by a Pine with a version number less than 4.50. If you believe that you have changed this data with an older Pine more recently than you've changed it with this version of Alpine, then you can probably safely answer \"Yes\". If you do not understand why this has happened, you should probably answer \"No\" so that you don't use the corrupt data. Then you should investigate further."), special, special); tmp[sizeof(tmp)-1] = '\0'; so_puts(in_store, tmp); } else if(reason > 1){ snprintf(tmp, sizeof(tmp), _("Unexpected value for header \"%s\"</CENTER><P>The special header \"%s\" in the last message in the folder has an unexpected value (%s) after it. This is the right sort of value that Alpine would normally put there, but it doesn't match the value from the first message in the folder. This may indicate that something is wrong. Unless you understand why this has happened, you should probably answer \"No\" so that you don't use the corrupt data. Then you should investigate further."), special, special, (extra && *extra) ? extra : "?"); tmp[sizeof(tmp)-1] = '\0'; so_puts(in_store, tmp); } so_seek(in_store, 0L, 0); init_handles(&handles); gf_filter_init(); gf_link_filter(gf_html2plain, gf_html2plain_opt(NULL, ps_global->ttyo->screen_cols, non_messageview_margin(), &handles, NULL, GFHP_LOCAL_HANDLES)); gf_set_so_readc(&gc, in_store); gf_set_so_writec(&pc, out_store); gf_pipe(gc, pc); gf_clear_so_writec(out_store); gf_clear_so_readc(in_store); memset(&sargs, 0, sizeof(SCROLL_S)); sargs.text.handles = handles; sargs.text.text = so_text(out_store); sargs.text.src = CharStar; sargs.bar.title = _("REMOTE DATA FORGERY WARNING"); sargs.proc.tool = rd_answer_forge_warning; sargs.proc.data.p = (void *)&the_answer; sargs.keys.menu = &forge_keymenu; setbitmap(sargs.keys.bitmap); scrolltool(&sargs); if(the_answer == 'y'){ rv = 1; rd->flags |= USER_SAID_YES; } else if(rd) rd->flags |= USER_SAID_NO; ps_global->mangled_screen = 1; ps_global->painted_body_on_startup = 0; ps_global->painted_footer_on_startup = 0; so_give(&in_store); so_give(&out_store); free_handles(&handles); } else{ char *p = tmp; snprintf(p, sizeof(tmp), _("\nThe data in the remote %s folder\n\n %s\n\nlooks suspicious. The reason for the suspicion is\n\n "), foldertype, foldername); tmp[sizeof(tmp)-1] = '\0'; p += strlen(p); if(reason == -2){ snprintf(p, sizeof(tmp)-(p-tmp), _("header \"%s\" is missing\n\nThe special header \"%s\" is missing from the last message\nin the folder. This indicates that something is wrong.\nYou should probably answer \"No\" so that you don't use the corrupt data.\nThen you should investigate further.\n\n"), special, special); tmp[sizeof(tmp)-1] = '\0'; } else if(reason == -1){ snprintf(p, sizeof(tmp)-(p-tmp), _("\"Received\" headers detected\n\nThe last message in the folder contains \"Received\" headers.\nThis usually indicates that the message was put there by the\nmail delivery system. Alpine does not add those Received headers.\nYou should probably answer \"No\" so that you don't use the corrupt data.\nThen you should investigate further.\n\n")); tmp[sizeof(tmp)-1] = '\0'; } else if(reason == 0){ snprintf(p, sizeof(tmp)-(p-tmp), _("Unexpected value for header \"%s\"\n\nThe special header \"%s\" in the last message in the folder\nhas an unexpected value (%s) after it. This probably\nindicates that something is wrong. This value would not normally be put\nthere by Alpine. You should probably answer \"No\" so that you don't use\nthe corrupt data. Then you should investigate further.\n\n"), special, special, (extra && *extra) ? extra : "?"); tmp[sizeof(tmp)-1] = '\0'; } else if(reason == 1){ snprintf(p, sizeof(tmp)-(p-tmp), _("Unexpected value for header \"%s\"\n\nThe special header \"%s\" in the last message in the folder\nhas an unexpected value (1) after it. It appears that it may have been\nput there by a Pine with a version number less than 4.50.\nIf you believe that you have changed this data with an older Pine more\nrecently than you've changed it with this version of Alpine, then you can\nprobably safely answer \"Yes\". If you do not understand why this has\nhappened, you should probably answer \"No\" so that you don't use the\ncorrupt data. Then you should investigate further.\n\n"), special, special); tmp[sizeof(tmp)-1] = '\0'; } else if(reason > 1){ snprintf(p, sizeof(tmp)-(p-tmp), _("Unexpected value for header \"%s\"\n\nThe special header \"%s\" in the last message in the folder\nhas an unexpected\nvalue (%s) after it. This is\nthe right sort of value that Alpine would normally put there, but it\ndoesn't match the value from the first message in the folder. This may\nindicate that something is wrong. Unless you understand why this has happened,\nyou should probably answer \"No\" so that you don't use the\ncorrupt data. Then you should investigate further.\n\n"), special, special, (extra && *extra) ? extra : "?"); tmp[sizeof(tmp)-1] = '\0'; } try_wantto: p += strlen(p); snprintf(p, sizeof(tmp)-(p-tmp), _("Suspicious data in \"%s\": Continue anyway "), (rd && rd->t.i.special_hdr) ? rd->t.i.special_hdr : unknown); tmp[sizeof(tmp)-1] = '\0'; if(want_to(tmp, 'n', 'x', NO_HELP, WT_NORM) == 'y'){ rv = 1; rd->flags |= USER_SAID_YES; } else if(rd) rd->flags |= USER_SAID_NO; } if(rv < 0) q_status_message1(SM_ORDER, 1, 3, _("Can't open remote %s"), (rd && rd->rn) ? rd->rn : "<noname>"); return(rv); }
/* * mc_cmd_bldr - construct a command string to execute * * If tmp_file is null, then the contents of the given MIME segment * is not provided. This is useful for building the "test=" string * as it doesn't operate on the segment's data. * * The return value is an alloc'd copy of the command to be executed. */ char * mc_cmd_bldr(char *controlstring, int type, char *subtype, BODY *body, char *tmp_file, char **err) { char *from, *to, *s, *parm; int prefixed = 0, used_tmp_file = 0; dprint((8, "- mc_cmd_bldr -\n")); for(from = controlstring, to = tmp_20k_buf; *from; ++from){ if(prefixed){ /* previous char was % */ prefixed = 0; switch(*from){ case '%': /* turned \% into this earlier */ if(to-tmp_20k_buf < SIZEOF_20KBUF) *to++ = '%'; break; case 's': /* insert tmp_file name in cmd */ if(tmp_file){ used_tmp_file = 1; sstrncpy(&to, tmp_file, SIZEOF_20KBUF-(to-tmp_20k_buf)); } else dprint((1, "mc_cmd_bldr: %%s in cmd but not supplied!\n")); break; case 't': /* insert MIME type/subtype */ /* quote to prevent funny business */ if(to-tmp_20k_buf < SIZEOF_20KBUF) *to++ = '\''; sstrncpy(&to, body_type_names(type), SIZEOF_20KBUF-(to-tmp_20k_buf)); if(to-tmp_20k_buf < SIZEOF_20KBUF) *to++ = '/'; sstrncpy(&to, subtype, SIZEOF_20KBUF-(to-tmp_20k_buf)); if(to-tmp_20k_buf < SIZEOF_20KBUF) *to++ = '\''; break; case '{': /* insert requested MIME param */ if(F_OFF(F_DO_MAILCAP_PARAM_SUBST, ps_global)){ int save; dprint((2, "mc_cmd_bldr: param subs %s\n", from ? from : "?")); if(err){ if((s = strindex(from, '}')) != NULL){ save = *++s; *s = '\0'; } snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Mailcap: see hidden feature %.200s (%%%.200s)", feature_list_name(F_DO_MAILCAP_PARAM_SUBST), from); *err = tmp_20k_buf; if(s) *s = save; } return(NULL); } s = strindex(from, '}'); if(!s){ q_status_message1(SM_ORDER, 0, 4, "Ignoring ill-formed parameter reference in mailcap file: %.200s", from); break; } *s = '\0'; ++from; /* from is the part inside the brackets now */ parm = parameter_val(body ? body->parameter : NULL, from); dprint((9, "mc_cmd_bldr: parameter %s = %s\n", from ? from : "?", parm ? parm : "(not found)")); /* * Quote parameter values for /bin/sh. * Put single quotes around the whole thing but every time * there is an actual single quote put it outside of the * single quotes with a backslash in front of it. So the * parameter value fred's car * turns into 'fred'\''s car' */ if(to-tmp_20k_buf < SIZEOF_20KBUF) *to++ = '\''; /* opening quote */ if(parm){ char *p; /* * Copy value, but quote single quotes for /bin/sh * Backslash quote is ignored inside single quotes so * have to put those outside of the single quotes. * (The parm+1000 nonsense is to protect against * malicious mail trying to overflow our buffer.) * * TCH - Change 2/8/1999 * Also quote the ` to prevent execution of arbitrary code */ for(p = parm; *p && p < parm+1000; p++){ if((*p == '\'') || (*p == '`')){ if(to-tmp_20k_buf+4 < SIZEOF_20KBUF){ *to++ = '\''; /* closing quote */ *to++ = '\\'; *to++ = *p; /* quoted character */ *to++ = '\''; /* opening quote */ } } else if(to-tmp_20k_buf < SIZEOF_20KBUF) *to++ = *p; } fs_give((void **) &parm); } if(to-tmp_20k_buf < SIZEOF_20KBUF) *to++ = '\''; /* closing quote for /bin/sh */ *s = '}'; /* restore */ from = s; break; /* * %n and %F are used by metamail to support otherwise * unrecognized multipart Content-Types. Pine does * not use these since we're only dealing with the individual * parts at this point. */ case 'n': case 'F': default: dprint((9, "Ignoring %s format code in mailcap file: %%%c\n", (*from == 'n' || *from == 'F') ? "unimplemented" : "unrecognized", *from)); break; } } else if(*from == '%') /* next char is special */ prefixed = 1; else if(to-tmp_20k_buf < SIZEOF_20KBUF) /* regular character, just copy */ *to++ = *from; } if(to-tmp_20k_buf < SIZEOF_20KBUF) *to = '\0'; tmp_20k_buf[SIZEOF_20KBUF-1] = '\0'; /* * file not specified, redirect to stdin */ if(!used_tmp_file && tmp_file) snprintf(to, SIZEOF_20KBUF-(to-tmp_20k_buf), MC_ADD_TMP, tmp_file); return(cpystr(tmp_20k_buf)); }
int incoming_monitoring_list_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) { int rv = 0; CONTEXT_S *cntxt; char **the_list; CONF_S *ctmp; char ***alval; OPT_SCREEN_S *saved_screen; if(cmd != MC_EXIT && fixed_var((*cl)->var, NULL, NULL)) return(rv); switch(cmd){ case MC_ADD: case MC_EDIT: cntxt = ps->context_list; if(!(cntxt && cntxt->use & CNTXT_INCMNG)){ q_status_message1(SM_ORDER, 3, 3, _("Turn on incoming folders with Config feature \"%s\""), pretty_feature_name(feature_list_name(F_ENABLE_INCOMING), -1)); return(rv); } saved_screen = opt_screen; the_list = adjust_list_of_monitored_incoming(cntxt, ew, V_INCCHECKLIST); /* adjust top if it might be necessary */ for(ctmp = (*cl)->varnamep; ctmp && ctmp->varnamep == (*cl)->varnamep; ctmp = next_confline(ctmp)) if(ctmp == opt_screen->top_line) opt_screen->top_line = (*cl)->varnamep; if(the_list){ alval = ALVAL((*cl)->var, ew); free_list_array(alval); if(!*the_list){ q_status_message(SM_ORDER, 0, 3, _("Using default, monitor all incoming folders")); if(alval){ /* * Remove config lines except for first one. */ *cl = (*cl)->varnamep; while((*cl)->next && (*cl)->next->varnamep == (*cl)->varnamep) snip_confline(&(*cl)->next); } } else config_add_list(ps, cl, the_list, NULL, 0); /* only have to free the top-level pointer */ fs_give((void **) &the_list); rv = 1; } else{ if(LVAL((*cl)->var, ew)) q_status_message(SM_ORDER, 0, 3, _("List is unchanged")); else q_status_message(SM_ORDER, 0, 3, _("Using default, monitor all incoming folders")); } opt_screen = saved_screen; ps->mangled_screen = 1; break; default: rv = text_tool(ps, cmd, cl, flags); /* if we deleted last one, reverts to default */ if(cmd == MC_DELETE && rv == 1 && (*cl)->varmem == 0 && (!(*cl)->next || (*cl)->next->varnamep != (*cl))) q_status_message(SM_ORDER, 0, 3, _("Using default, monitor all incoming folders")); break; } /* * This is just like the end of text_tool. */ if(rv == 1){ /* * Now go and set the current_val based on user_val changes * above. Turn off command line settings... */ set_current_val((*cl)->var, TRUE, FALSE); fix_side_effects(ps, (*cl)->var, 0); if((*cl)->value) fs_give((void **) &(*cl)->value); (*cl)->value = pretty_value(ps, *cl); exception_override_warning((*cl)->var); } return(rv); }
/*---------------------------------------------------------------------- Read input characters with lots of processing for arrow keys and such (UNIX) Args: time_out -- The timeout to for the reads Result: returns the character read. Possible special chars. This deals with function and arrow keys as well. The idea is that this routine handles all escape codes so it done in only one place. Especially so the back arrow key can work when entering things on a line. Also so all function keys can be disabled and not cause weird things to happen. ---*/ UCS read_char(int time_out) { UCS status, cc, ch; int (*key_rec)(int); key_rec = key_recorder; if(ps_global->conceal_sensitive_debugging) key_rec = NULL; /* Get input from initial-keystrokes */ if(process_config_input(&cc)){ ch = cc; return(ch); } if((ch = check_for_timeout(time_out)) != READY_TO_READ) goto done; switch(status = kbseq(pine_simple_ttgetc, key_rec, read_bail, ps_global->input_cs, &ch)){ case KEY_DOUBLE_ESC: /* * Special hack to get around comm devices eating control characters. */ if(check_for_timeout(5) != READY_TO_READ){ dprint((9, "Read char: incomplete double escape timed out...\n")); ch = KEY_JUNK; /* user typed ESC ESC, then stopped */ goto done; } else ch = READ_A_CHAR(); ch &= 0x7f; /* We allow a 3-digit number between 001 and 255 */ if(isdigit((unsigned char) ch)){ int n = 0, i = ch - '0'; if(i < 0 || i > 2){ dprint((9, "Read char: double escape followed by 1st digit not 0, 1, or 2... (%d)\n", i)); ch = KEY_JUNK; goto done; /* bogus literal char value */ } while(n++ < 2){ if(check_for_timeout(5) != READY_TO_READ || (!isdigit((unsigned char) (ch = READ_A_CHAR())) || (n == 1 && i == 2 && ch > '5') || (n == 2 && i == 25 && ch > '5'))){ dprint((9, "Read char: bad double escape, either timed out or too large 3-digit num...\n")); ch = KEY_JUNK; /* user typed ESC ESC #, stopped */ goto done; } i = (i * 10) + (ch - '0'); } ch = i; } else{ /* or, normal case, ESC ESC c means ^c */ if(islower((unsigned char) ch)) /* canonicalize if alpha */ ch = toupper((unsigned char) ch); ch = (isalpha((unsigned char)ch) || ch == '@' || (ch >= '[' && ch <= '_')) ? ctrl(ch) : ((ch == SPACE) ? ctrl('@'): ch); dprint((9, "Read char: this is a successful double escape...\n")); } goto done; #ifdef MOUSE case KEY_XTERM_MOUSE: if(mouseexist()){ /* * Special hack to get mouse events from an xterm. * Get the details, then pass it past the keymenu event * handler, and then to the installed handler if there * is one... */ static int down = 0; int x, y, button; unsigned long cmd; clear_cursor_pos(); button = READ_A_CHAR() & 0x03; x = READ_A_CHAR() - '!'; y = READ_A_CHAR() - '!'; ch = NO_OP_COMMAND; if(button == 0){ /* xterm button 1 down */ down = 1; if(checkmouse(&cmd, 1, x, y)) ch = cmd; } else if (down && button == 3){ down = 0; if(checkmouse(&cmd, 0, x, y)) ch = cmd; } goto done; } break; #endif /* MOUSE */ case KEY_UP : case KEY_DOWN : case KEY_RIGHT : case KEY_LEFT : case KEY_PGUP : case KEY_PGDN : case KEY_HOME : case KEY_END : case KEY_DEL : case PF1 : case PF2 : case PF3 : case PF4 : case PF5 : case PF6 : case PF7 : case PF8 : case PF9 : case PF10 : case PF11 : case PF12 : dprint((9, "Read char returning: 0x%x %s\n", status, pretty_command(status))); return(status); case CTRL_KEY_UP : status = KEY_UP; dprint((9, "Read char returning: 0x%x %s (for CTRL_KEY_UP)\n", status, pretty_command(status))); return(status); case CTRL_KEY_DOWN : status = KEY_DOWN; dprint((9, "Read char returning: 0x%x %s (for CTRL_KEY_DOWN)\n", status, pretty_command(status))); return(status); case CTRL_KEY_RIGHT : status = KEY_RIGHT; dprint((9, "Read char returning: 0x%x %s (for CTRL_KEY_RIGHT)\n", status, pretty_command(status))); return(status); case CTRL_KEY_LEFT : status = KEY_LEFT; dprint((9, "Read char returning: 0x%x %s (for CTRL_KEY_LEFT)\n", status, pretty_command(status))); return(status); case KEY_SWALLOW_Z: status = KEY_JUNK; case KEY_SWAL_UP: case KEY_SWAL_DOWN: case KEY_SWAL_LEFT: case KEY_SWAL_RIGHT: do if(check_for_timeout(2) != READY_TO_READ){ status = KEY_JUNK; break; } while(!strchr("~qz", READ_A_CHAR())); ch = (status == KEY_JUNK) ? status : status - (KEY_SWAL_UP - KEY_UP); goto done; case KEY_KERMIT: do{ cc = ch; if(check_for_timeout(2) != READY_TO_READ){ status = KEY_JUNK; break; } else ch = READ_A_CHAR(); }while(cc != '\033' && ch != '\\'); ch = KEY_JUNK; goto done; case BADESC: ch = KEY_JUNK; goto done; case 0: /* regular character */ default: /* * we used to strip (ch &= 0x7f;), but this seems much cleaner * in the face of line noise and has the benefit of making it * tougher to emit mistakenly labeled MIME... */ if((ch & ~0x7f) && ((!ps_global->keyboard_charmap || !strucmp(ps_global->keyboard_charmap, "US-ASCII")) && (!ps_global->display_charmap || !strucmp(ps_global->display_charmap, "US-ASCII")))){ dprint((9, "Read char sees ch = 0x%x status=0x%x, returns KEY_JUNK\n", ch, status)); return(KEY_JUNK); } else if(ch == ctrl('Z')){ dprint((9, "Read char got ^Z, calling do_suspend\n")); ch = do_suspend(); dprint((9, "After do_suspend Read char returns 0x%x %s\n", ch, pretty_command(ch))); return(ch); } #ifdef MOUSE else if(ch == ctrl('\\')){ int e; dprint((9, "Read char got ^\\, toggle xterm mouse\n")); if(F_ON(F_ENABLE_MOUSE, ps_global)){ (e=mouseexist()) ? end_mouse() : (void) init_mouse(); if(e != mouseexist()) q_status_message1(SM_ASYNC, 0, 2, "Xterm mouse tracking %s!", mouseexist() ? "on" : "off"); else if(!e) q_status_message1(SM_ASYNC, 0, 2, "See help for feature \"%s\" ($DISPLAY variable set?)", pretty_feature_name(feature_list_name(F_ENABLE_MOUSE), -1)); } else q_status_message1(SM_ASYNC, 0, 2, "Feature \"%s\" not enabled", pretty_feature_name(feature_list_name(F_ENABLE_MOUSE), -1)); return(NO_OP_COMMAND); } #endif /* MOUSE */ done: #ifdef DEBUG if(ps_global->conceal_sensitive_debugging && debug < 10){ dprint((9, "Read char returning: <hidden char>\n")); } else{ dprint((9, "Read char returning: 0x%x %s\n", ch, pretty_command(ch))); } #endif return(ch); } /* not reachable */ return(KEY_JUNK); }
/*---------------------------------------------------------------------- Open the printer Args: desc -- Description of item to print. Should have one trailing blank. Return value: < 0 is a failure. 0 a success. This does most of the work of popen so we can save the standard output of the command we execute and send it back to the user. ----*/ int open_printer(char *desc) { #ifndef _WINDOWS char command[201], prompt[200]; int cmd, rc, just_one; char *p, *init, *nick; char aname[100], wname[100]; char *printer; int done = 0, i, lastprinter, cur_printer = 0; HelpType help; char **list; static ESCKEY_S ekey[] = { /* TRANSLATORS: these are command labels for printing screen */ {'y', 'y', "Y", N_("Yes")}, {'n', 'n', "N", N_("No")}, /* TRANSLATORS: go to Previous Printer in list */ {ctrl('P'), 10, "^P", N_("Prev Printer")}, {ctrl('N'), 11, "^N", N_("Next Printer")}, {-2, 0, NULL, NULL}, /* TRANSLATORS: use Custom Print command */ {'c', 'c', "C", N_("CustomPrint")}, {KEY_UP, 10, "", ""}, {KEY_DOWN, 11, "", ""}, {-1, 0, NULL, NULL}}; #define PREV_KEY 2 #define NEXT_KEY 3 #define CUSTOM_KEY 5 #define UP_KEY 6 #define DOWN_KEY 7 trailer = NULL; init = NULL; nick = NULL; command[sizeof(command)-1] = '\0'; if(ps_global->VAR_PRINTER == NULL){ q_status_message(SM_ORDER | SM_DING, 3, 5, "No printer has been chosen. Use SETUP on main menu to make choice."); return(-1); } /* Is there just one print command available? */ just_one = (ps_global->printer_category!=3&&ps_global->printer_category!=2) || (ps_global->printer_category == 2 && !(ps_global->VAR_STANDARD_PRINTER && ps_global->VAR_STANDARD_PRINTER[0] && ps_global->VAR_STANDARD_PRINTER[1])) || (ps_global->printer_category == 3 && !(ps_global->VAR_PERSONAL_PRINT_COMMAND && ps_global->VAR_PERSONAL_PRINT_COMMAND[0] && ps_global->VAR_PERSONAL_PRINT_COMMAND[1])); if(F_ON(F_CUSTOM_PRINT, ps_global)) ekey[CUSTOM_KEY].ch = 'c'; /* turn this key on */ else ekey[CUSTOM_KEY].ch = -2; /* turn this key off */ if(just_one){ ekey[PREV_KEY].ch = -2; /* turn these keys off */ ekey[NEXT_KEY].ch = -2; ekey[UP_KEY].ch = -2; ekey[DOWN_KEY].ch = -2; } else{ ekey[PREV_KEY].ch = ctrl('P'); /* turn these keys on */ ekey[NEXT_KEY].ch = ctrl('N'); ekey[UP_KEY].ch = KEY_UP; ekey[DOWN_KEY].ch = KEY_DOWN; /* * count how many printers in list and find the default in the list */ if(ps_global->printer_category == 2) list = ps_global->VAR_STANDARD_PRINTER; else list = ps_global->VAR_PERSONAL_PRINT_COMMAND; for(i = 0; list[i]; i++) if(strcmp(ps_global->VAR_PRINTER, list[i]) == 0) cur_printer = i; lastprinter = i - 1; } help = NO_HELP; ps_global->mangled_footer = 1; while(!done){ if(init) fs_give((void **)&init); if(trailer) fs_give((void **)&trailer); if(just_one) printer = ps_global->VAR_PRINTER; else printer = list[cur_printer]; parse_printer(printer, &nick, &p, &init, &trailer, NULL, NULL); strncpy(command, p, sizeof(command)-1); command[sizeof(command)-1] = '\0'; fs_give((void **)&p); /* TRANSLATORS: Print something1 using something2. For example, Print configuration using printer three. */ snprintf(prompt, sizeof(prompt), _("Print %s using \"%s\" ? "), desc ? desc : "", *nick ? nick : command); prompt[sizeof(prompt)-1] = '\0'; fs_give((void **)&nick); cmd = radio_buttons(prompt, -FOOTER_ROWS(ps_global), ekey, 'y', 'x', help, RB_NORM); switch(cmd){ case 'y': q_status_message1(SM_ORDER, 0, 9, "Printing with command \"%s\"", command); done++; break; case 10: cur_printer = (cur_printer>0) ? (cur_printer-1) : lastprinter; break; case 11: cur_printer = (cur_printer<lastprinter) ? (cur_printer+1) : 0; break; case 'n': case 'x': done++; break; case 'c': done++; break; default: break; } } if(cmd == 'c'){ if(init) fs_give((void **)&init); if(trailer) fs_give((void **)&trailer); snprintf(prompt, sizeof(prompt), "Enter custom command : "); prompt[sizeof(prompt)-1] = '\0'; command[0] = '\0'; rc = 1; help = NO_HELP; while(rc){ int flags = OE_APPEND_CURRENT; rc = optionally_enter(command, -FOOTER_ROWS(ps_global), 0, sizeof(command), prompt, NULL, help, &flags); if(rc == 1){ cmd = 'x'; rc = 0; } else if(rc == 3) help = (help == NO_HELP) ? h_custom_print : NO_HELP; else if(rc == 0){ removing_trailing_white_space(command); removing_leading_white_space(command); q_status_message1(SM_ORDER, 0, 9, "Printing with command \"%s\"", command); } } } if(cmd == 'x' || cmd == 'n'){ q_status_message(SM_ORDER, 0, 2, "Print cancelled"); if(init) fs_give((void **)&init); if(trailer) fs_give((void **)&trailer); return(-1); } display_message('x'); ps_global->print = (PRINT_S *)fs_get(sizeof(PRINT_S)); memset(ps_global->print, 0, sizeof(PRINT_S)); strncpy(aname, ANSI_PRINTER, sizeof(aname)-1); aname[sizeof(aname)-1] = '\0'; strncat(aname, "-no-formfeed", sizeof(aname)-strlen(aname)-1); strncpy(wname, WYSE_PRINTER, sizeof(wname)-1); wname[sizeof(wname)-1] = '\0'; strncat(wname, "-no-formfeed", sizeof(wname)-strlen(wname)-1); if(strucmp(command, ANSI_PRINTER) == 0 || strucmp(command, aname) == 0 || strucmp(command, WYSE_PRINTER) == 0 || strucmp(command, wname) == 0){ /*----------- Attached printer ---------*/ q_status_message(SM_ORDER, 0, 9, "Printing to attached desktop printer..."); display_message('x'); xonxoff_proc(1); /* make sure XON/XOFF used */ crlf_proc(1); /* AND LF->CR xlation */ if(strucmp(command, ANSI_PRINTER) == 0 || strucmp(command, aname) == 0){ fputs("\033[5i", stdout); ansi_off = 1; } else{ ansi_off = 0; printf("%c", 18); /* aux on for wyse60, Chuck Everett <*****@*****.**> */ } ps_global->print->fp = stdout; if(strucmp(command, ANSI_PRINTER) == 0 || strucmp(command, WYSE_PRINTER) == 0){ /* put formfeed at the end of the trailer string */ if(trailer){ int len = strlen(trailer); fs_resize((void **)&trailer, len+2); trailer[len] = '\f'; trailer[len+1] = '\0'; } else trailer = cpystr("\f"); } } else{ /*----------- Print by forking off a UNIX command ------------*/ dprint((4, "Printing using command \"%s\"\n", command ? command : "?")); ps_global->print->result = temp_nam(NULL, "pine_prt"); if(ps_global->print->result && (ps_global->print->pipe = open_system_pipe(command, &ps_global->print->result, NULL, PIPE_WRITE | PIPE_STDERR, 0, pipe_callback, NULL))){ ps_global->print->fp = ps_global->print->pipe->out.f; } else{ if(ps_global->print->result){ our_unlink(ps_global->print->result); fs_give((void **)&ps_global->print->result); } q_status_message1(SM_ORDER | SM_DING, 3, 4, "Error opening printer: %s", error_description(errno)); dprint((2, "Error popening printer \"%s\"\n", error_description(errno))); if(init) fs_give((void **)&init); if(trailer) fs_give((void **)&trailer); return(-1); } } ps_global->print->err = 0; if(init){ if(*init) fputs(init, ps_global->print->fp); fs_give((void **)&init); } cb.cbuf[0] = '\0'; cb.cbufp = cb.cbuf; cb.cbufend = cb.cbuf; #else /* _WINDOWS */ int status; LPTSTR desclpt = NULL; if(desc) desclpt = utf8_to_lptstr(desc); if (status = mswin_print_ready (0, desclpt)) { q_status_message1(SM_ORDER | SM_DING, 3, 4, "Error starting print job: %s", mswin_print_error(status)); if(desclpt) fs_give((void **) &desclpt); return(-1); } if(desclpt) fs_give((void **) &desclpt); q_status_message(SM_ORDER, 0, 9, "Printing to windows printer..."); display_message('x'); /* init print control structure */ ps_global->print = (PRINT_S *)fs_get(sizeof(PRINT_S)); memset(ps_global->print, 0, sizeof(PRINT_S)); ps_global->print->err = 0; #endif /* _WINDOWS */ return(0); }
/*---------------------------------------------------------------------- Suspend Pine. Reset tty and suspend. Suspend is finished when this returns Args: The pine structure Result: Execution suspended for a while. Screen will need redrawing after this is done. Instead of the usual handling of ^Z by catching a signal, we actually read the ^Z and then clean up the tty driver, then kill ourself to stop, and pick up where we left off when execution resumes. ----------------------------------------------------------------------*/ UCS do_suspend(void) { struct pine *pine = ps_global; time_t now; UCS retval; #if defined(DOS) || defined(OS2) int result, orig_cols, orig_rows; #else int isremote; #endif #ifdef DOS static char *shell = NULL; #define STD_SHELL "COMMAND.COM" #else #ifdef OS2 static char *shell = NULL; #define STD_SHELL "CMD.EXE" #endif #endif if(!have_job_control()) { bogus_command(ctrl('Z'), F_ON(F_USE_FK, pine) ? "F1" : "?"); return(NO_OP_COMMAND); } if(F_OFF(F_CAN_SUSPEND, pine)) { q_status_message(SM_ORDER | SM_DING, 3, 3, _("Alpine suspension not enabled - see help text")); return(NO_OP_COMMAND); } #ifdef _WINDOWS mswin_minimize(); return(NO_OP_COMMAND); #else isremote = (ps_global->mail_stream && ps_global->mail_stream->mailbox && (*ps_global->mail_stream->mailbox == '{' || (*ps_global->mail_stream->mailbox == '*' && *(ps_global->mail_stream->mailbox + 1) == '{'))); now = time((time_t *)0); dprint((1, "\n\n --- %s - SUSPEND ---- %s", isremote ? "REMOTE" : "LOCAL", ctime(&now))); ttyfix(0); #if defined(DOS) || defined(OS2) suspend_notice("exit"); if (!shell) { char *p; if (!((shell = getenv("SHELL")) || (shell = getenv("COMSPEC")))) shell = STD_SHELL; shell = cpystr(shell); /* copy in free storage */ for(p = shell; (p = strchr(p, '/')); p++) *p = '\\'; } result = system(shell); #else if(F_ON(F_SUSPEND_SPAWNS, ps_global)) { PIPE_S *syspipe; if((syspipe = open_system_pipe(NULL, NULL, NULL, PIPE_USER|PIPE_RESET, 0, pipe_callback, pipe_report_error)) != NULL) { suspend_notice("exit"); #ifndef SIGCHLD if(isremote) suspend_warning(); #endif (void) close_system_pipe(&syspipe, NULL, pipe_callback); } } else { suspend_notice("fg"); if(isremote) suspend_warning(); stop_process(); } #endif /* DOS */ now = time((time_t *)0); dprint((1, "\n\n ---- RETURN FROM SUSPEND ---- %s", ctime(&now))); ttyfix(1); #if defined(DOS) || defined(OS2) orig_cols = pine->ttyo->screen_cols; orig_rows = pine->ttyo->screen_rows; #endif fix_windsize(pine); #if defined(DOS) || defined(OS2) if(orig_cols != pine->ttyo->screen_cols || orig_rows != pine->ttyo->screen_rows) retval = KEY_RESIZE; else #endif retval = ctrl('L');; #if defined(DOS) || defined(OS2) if(result == -1) q_status_message1(SM_ORDER | SM_DING, 3, 4, _("Error loading \"%s\""), shell); #endif if(isremote && !pine_mail_ping(ps_global->mail_stream)) q_status_message(SM_ORDER | SM_DING, 4, 9, _("Suspended for too long, IMAP connection broken")); return(retval); #endif /* !_WINDOWS */ }
/* * pipe_callback - handle pine-specific pipe setup like child * signal handler and possibly any display stuff * BUG: this function should probably be in a "alpine/pipe.c" */ void pipe_callback(PIPE_S *syspipe, int flags, void *data) { #ifdef _WINDOWS bitmap_t bitmap; #endif if(flags & OSB_PRE_OPEN) { dprint((5, "Opening pipe: (%s%s%s%s%s%s)\n", (syspipe->mode & PIPE_WRITE) ? "W":"", (syspipe->mode & PIPE_READ) ? "R":"", (syspipe->mode & PIPE_NOSHELL) ? "N":"", (syspipe->mode & PIPE_PROT) ? "P":"", (syspipe->mode & PIPE_USER) ? "U":"", (syspipe->mode & PIPE_RESET) ? "T":"")); #ifdef _WINDOWS q_status_message(SM_ORDER, 0, 0, "Waiting for called program to finish..."); flush_status_messages(1); setbitmap(bitmap); draw_keymenu(&pipe_cancel_keymenu, bitmap, ps_global->ttyo->screen_cols, 1-FOOTER_ROWS(ps_global), 0, FirstMenu); #else /* UNIX */ if(!(syspipe->mode & (PIPE_WRITE | PIPE_READ)) && !(syspipe->mode & PIPE_SILENT)) { flush_status_messages(0); /* just clean up display */ ClearScreen(); fflush(stdout); } if(syspipe->mode & PIPE_RESET) ttyfix(0); #ifdef SIGCHLD /* * Prepare for demise of child. Use SIGCHLD if it's available so * we can do useful things, like keep the IMAP stream alive, while * we're waiting on the child. The handler may have been changed by * something in the composer, in particular, by an alt_editor call. * So we need to re-set it to child_signal and then set it back * when we're done. */ child_signalled = child_jump = 0; syspipe->chld = signal(SIGCHLD, child_signal); #endif #endif /* UNIX */ } else if(flags & OSB_POST_OPEN) { #ifdef _WINDOWS clearfooter(ps_global); ps_global->mangled_footer = 1; if((int) data == -2) q_status_message1(SM_ORDER, 2, 3, "Ignoring completion of %s", syspipe->command); #else /* UNIX */ if(!(syspipe->mode & (PIPE_WRITE | PIPE_READ)) && !(syspipe->mode & PIPE_SILENT)) { ClearScreen(); ps_global->mangled_screen = 1; } if(syspipe->mode & PIPE_RESET) ttyfix(1); #ifdef SIGCHLD (void) signal(SIGCHLD, SIG_DFL); #endif #endif /* UNIX */ } else if(flags & OSB_PRE_CLOSE) { #ifdef SIGCHLD /* * this is here so close_system_pipe so it has something * to do while we're waiting on the other end of the * pipe to complete. When we're in the background for * a shell, the the side effect is pinging */ RETSIGTYPE (*alarm_sig)(); int old_cue = F_ON(F_SHOW_DELAY_CUE, ps_global); /* * remember the current SIGALRM handler, and make sure it's * installed when we're finished just in case the longjmp * out of the SIGCHLD handler caused sleep() to lose it. * Don't pay any attention to that man behind the curtain. */ alarm_sig = signal(SIGALRM, SIG_IGN); (void) F_SET(F_SHOW_DELAY_CUE, ps_global, 0); ps_global->noshow_timeout = 1; while(!child_signalled) { /* wake up and prod server */ if(!(syspipe->mode & PIPE_NONEWMAIL)) new_mail(0, 2, (syspipe->mode & PIPE_RESET) ? NM_NONE : NM_DEFER_SORT); if(!child_signalled) { if(setjmp(child_state) == 0) { child_jump = 1; /* prepare to wake up */ sleep(600); /* give it 5mins to happend */ } else our_sigunblock(SIGCHLD); } child_jump = 0; } ps_global->noshow_timeout = 0; F_SET(F_SHOW_DELAY_CUE, ps_global, old_cue); (void) signal(SIGALRM, alarm_sig); (void) signal(SIGCHLD, syspipe->chld); #endif } else if(flags & OSB_POST_CLOSE) { if(syspipe->mode & PIPE_RESET) /* restore our tty modes */ ttyfix(1); if(!(syspipe->mode & (PIPE_WRITE | PIPE_READ | PIPE_SILENT))) { ClearScreen(); /* No I/O to forked child */ ps_global->mangled_screen = 1; } } }
/* ---------------------------------------------------------------------- Execute the given mailcap command Args: cmd -- the command to execute image_file -- the file the data is in needsterminal -- does this command want to take over the terminal? ----*/ void exec_mailcap_cmd(MCAP_CMD_S *mc_cmd, char *image_file, int needsterminal) { #ifdef _WINDOWS STARTUPINFO start_info; PROCESS_INFORMATION proc_info; WINHAND childProcess; int success = 0; char *cmd; LPTSTR image_file_lpt = NULL; LPTSTR cmd_lpt = NULL; /* no special handling yet, but could be used to replace '*' hack */ if(mc_cmd) cmd = mc_cmd->command; else return; dprint((9, "run_viewer: command=%s\n", cmd ? cmd : "?")) ; if(image_file) image_file_lpt = utf8_to_lptstr(image_file); /* Set to READONLY so the viewer can't try to edit it and keep it around */ if(image_file_lpt) SetFileAttributes(image_file_lpt, FILE_ATTRIBUTE_READONLY); if(*cmd == '*' || (*cmd == '\"' && *(cmd+1) == '*')){ /* * It has been asked that there be the ability to do an * "Open With..." on attachments like you can from the * Windows file browser. After looking into this, it * seems that the only way to do this would be through * an undocumented hack. Here, we would pass "openas" as * the verb to mswin_shell_exec (also some changes in * mswin_shell_exec). Since this is the delicate world * of attachment handling, it seems right not to rely on * a hack. The interface wouldn't be too clean anyways, * as we would have to download the attachment only to * display the "Open With..." dialog. Go figure, some * things Microsoft just wants to keep to themselves. */ /* * 2/1/2007. No idea when the above comment was written, but it is * documented now at least. The below two urls describe the "openas" verb: * * http://blogs.msdn.com/oldnewthing/archive/2004/11/26/270710.aspx * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ * shellcc/platform/shell/programmersguide/shell_basics/ * shell_basics_extending/context.asp */ success = mswin_shell_exec(cmd, &childProcess) == 0; } else{ memset(&proc_info, 0, sizeof(proc_info)); memset(&start_info, 0, sizeof(start_info)); start_info.dwFlags = STARTF_FORCEONFEEDBACK; start_info.wShowWindow = SW_SHOWNORMAL; if(cmd) cmd_lpt = utf8_to_lptstr(cmd); if(CreateProcess(NULL, cmd_lpt, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, NULL, NULL, &start_info, &proc_info) == TRUE){ q_status_message(SM_ORDER, 0, 4, "VIEWER command completed"); dprint ((3, "CreatProcess(%s) Success.\n", cmd ? cmd : "?")); childProcess = proc_info.hProcess; success = 1; } if(cmd_lpt) fs_give((void **) &cmd_lpt); } if(!success){ int rc = (int) GetLastError(); if(image_file_lpt) SetFileAttributes(image_file_lpt, FILE_ATTRIBUTE_NORMAL); our_unlink(image_file); q_status_message2(SM_ORDER, 3, 4, "\007Can't start viewer. %s%s.", (rc == 2 || rc == 3) ? "Viewer not found: " : (rc == 8) ? "Not enough memory" : "Windows error ", (rc == 2 || rc == 3) ? cmd : (rc == 8) ? "" : int2string(rc)); } if(image_file_lpt) fs_give((void **) &image_file_lpt); #elif OSX_TARGET char *command = NULL, *result_file = NULL, *p; char **r_file_h; PIPE_S *syspipe; int mode; if(!mc_cmd) return; if(mc_cmd->special_handling){ char *rhost; if(mime_os_specific_access()) osx_launch_special_handling(mc_cmd, image_file); else{ q_status_message(SM_ORDER, 0, 4, "VIEWER command cancelled"); our_unlink(image_file); } } else { char *cmd = mc_cmd->command; size_t l; l = 32 + strlen(cmd) + (2*strlen(image_file)); p = command = (char *) fs_get((l+1) * sizeof(char)); if(!needsterminal) /* put in background if it doesn't need terminal */ *p++ = '('; snprintf(p, l+1-(p-command), "%s", cmd); p += strlen(p); if(!needsterminal){ if(p-command+2 < l+1){ *p++ = ')'; *p++ = ' '; *p++ = '&'; } } if(p-command < l+1) *p++ = '\n'; if(p-command < l+1) *p = '\0'; dprint((9, "exec_mailcap_cmd: command=%s\n", command ? command : "?")); mode = PIPE_RESET; if(needsterminal == 1) r_file_h = NULL; else{ mode |= PIPE_WRITE | PIPE_STDERR; result_file = temp_nam(NULL, "pine_cmd"); r_file_h = &result_file; } if(syspipe = open_system_pipe(command, r_file_h, NULL, mode, 0, pipe_callback, NULL)){ close_system_pipe(&syspipe, NULL, pipe_callback); if(needsterminal == 1) q_status_message(SM_ORDER, 0, 4, "VIEWER command completed"); else if(needsterminal == 2) display_output_file(result_file, "VIEWER", " command result", 1); else display_output_file(result_file, "VIEWER", " command launched", 1); } else q_status_message1(SM_ORDER, 3, 4, "Cannot spawn command : %s", cmd); fs_give((void **)&command); if(result_file) fs_give((void **)&result_file); } #else char *command = NULL, *result_file = NULL, *p, *cmd, *q, *psef; char **r_file_h; PIPE_S *syspipe; int mode; size_t l; /* no os-specific command handling */ if(mc_cmd) cmd = mc_cmd->command; else return; #ifdef PSEFCMD psef = fs_get((60 + strlen(PSEFCMD) + strlen(image_file))*sizeof(char)); sprintf(psef, "PSEF=`%s | /bin/grep \"%s\" | /bin/grep -v grep`", PSEFCMD, image_file); q = fs_get((80 + 2*strlen(psef))*sizeof(char)); /* bigger than 62 */ sprintf(q, "/bin/sh -c '(%s; while test -n \"$PSEF\" ; do %s ; sleep %d ; done)' ;", psef, psef, ps_global->sleep); fs_give((void **) &psef); #else q = cpystr(""); #endif /* PSEFCMD */ l = 32 + strlen(cmd) + 2*strlen(image_file) + strlen(q); p = command = (char *)fs_get((l+1) * sizeof(char)); if(!needsterminal) /* put in background if it doesn't need terminal */ *p++ = '('; snprintf(p, l+1-(p-command), "%s ; %s rm -f %s", cmd, q, image_file); fs_give((void **)&q); command[l] = '\0'; p += strlen(p); if(!needsterminal && (p-command)+5 < l){ *p++ = ')'; *p++ = ' '; *p++ = '&'; } *p++ = '\n'; *p = '\0'; dprint((9, "exec_mailcap_cmd: command=%s\n", command ? command : "?")); mode = PIPE_RESET; if(needsterminal == 1) r_file_h = NULL; else{ mode |= PIPE_WRITE | PIPE_STDERR; result_file = temp_nam(NULL, "pine_cmd"); r_file_h = &result_file; } if((syspipe = open_system_pipe(command, r_file_h, NULL, mode, 0, pipe_callback, NULL)) != NULL){ close_system_pipe(&syspipe, NULL, pipe_callback); if(needsterminal == 1) q_status_message(SM_ORDER, 0, 4, "VIEWER command completed"); else if(needsterminal == 2) display_output_file(result_file, "VIEWER", " command result", 1); else display_output_file(result_file, "VIEWER", " command launched", 1); } else q_status_message1(SM_ORDER, 3, 4, "Cannot spawn command : %s", cmd); fs_give((void **)&command); if(result_file) fs_give((void **)&result_file); #endif }
int litsig_text_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags) { char **apval; int rv = 0; if(cmd != MC_EXIT && fixed_var((*cl)->var, NULL, NULL)) return(rv); apval = APVAL((*cl)->var, ew); switch(cmd){ case MC_ADD: case MC_EDIT : if(apval){ char *input = NULL, *result = NULL, *err = NULL, *cstring_version; char *olddefval = NULL, *start_with; size_t len; if(!*apval && (*cl)->var->current_val.p && (*cl)->var->current_val.p[0]){ if(!strncmp((*cl)->var->current_val.p, DSTRING, (len=strlen(DSTRING)))){ /* strip DSTRING and trailing paren */ olddefval = (char *)fs_get(strlen((*cl)->var->current_val.p)+1); strncpy(olddefval, (*cl)->var->current_val.p+len, strlen((*cl)->var->current_val.p)-len-1); olddefval[strlen((*cl)->var->current_val.p)-len-1] = '\0'; start_with = olddefval; } else{ olddefval = cpystr((*cl)->var->current_val.p); start_with = olddefval; } } else start_with = (*apval) ? *apval : ""; input = (char *)fs_get((strlen(start_with)+1) * sizeof(char)); input[0] = '\0'; cstring_to_string(start_with, input); err = signature_edit_lit(input, &result, ((*cl)->var == role_comment_ptr) ? "COMMENT EDITOR" : "SIGNATURE EDITOR", ((*cl)->var == role_comment_ptr) ? h_composer_commentedit : h_composer_sigedit); if(!err){ if(olddefval && !strcmp(input, result) && want_to(_("Leave unset and use default "), 'y', 'y', NO_HELP, WT_FLUSH_IN) == 'y'){ rv = 0; } else{ cstring_version = string_to_cstring(result); if(apval && *apval) fs_give((void **)apval); if(apval){ *apval = cstring_version; cstring_version = NULL; } if(cstring_version) fs_give((void **)&cstring_version); rv = 1; } } else rv = 0; if(err){ q_status_message1(SM_ORDER, 3, 5, "%s", err); fs_give((void **)&err); } if(result) fs_give((void **)&result); if(olddefval) fs_give((void **)&olddefval); if(input) fs_give((void **)&input); } ps->mangled_screen = 1; break; default: rv = text_tool(ps, cmd, cl, flags); break; } /* * At this point, if changes occurred, var->user_val.X is set. * So, fix the current_val, and handle special cases... * * NOTE: we don't worry about the "fixed variable" case here, because * editing such vars should have been prevented above... */ if(rv == 1){ /* * Now go and set the current_val based on user_val changes * above. Turn off command line settings... */ set_current_val((*cl)->var, TRUE, FALSE); if((*cl)->value) fs_give((void **)&(*cl)->value); (*cl)->value = pretty_value(ps, *cl); exception_override_warning((*cl)->var); /* * The value of literal sig can affect whether signature file is * used or not. So it affects what we display for sig file variable. */ if((*cl)->next && (*cl)->next->var == &ps->vars[V_SIGNATURE_FILE]){ if((*cl)->next->value) fs_give((void **)&(*cl)->next->value); (*cl)->next->value = pretty_value(ps, (*cl)->next); } } return(rv); }
/*---------------------------------------------------------------------- Handle fetching and filtering a text message segment to be displayed by scrolltool or printed or exported or piped. Args: att -- segment to fetch msgno -- message number segment is a part of pc -- function to write characters from segment with style -- Indicates special handling for error messages flags -- Indicates special necessary handling Returns: 1 if errors encountered, 0 if everything went A-OK ----*/ int decode_text(ATTACH_S *att, long int msgno, gf_io_t pc, HANDLE_S **handlesp, DetachErrStyle style, int flags) { FILTLIST_S filters[14]; char *err, *charset; int filtcnt = 0, error_found = 0, column, wrapit; int is_in_sig = OUT_SIG_BLOCK; int is_flowed_msg = 0, add_me = 1, doraw = RAWSTRING; int is_delsp_yes = 0; int filt_only_c0 = 0; char *parmval; char *free_this = NULL; STORE_S *warn_so = NULL; DELQ_S dq; URL_HILITE_S uh; column = (flags & FM_DISPLAY) ? ps_global->ttyo->screen_cols : 80; if(!(flags & FM_DISPLAY)) flags |= FM_NOINDENT; wrapit = column; memset(filters, 0, sizeof(filters)); /* charset the body part is in */ charset = parameter_val(att->body->parameter, "charset"); /* determined if it's flowed, affects wrapping and quote coloring */ if(att->body->type == TYPETEXT && !strucmp(att->body->subtype, "plain") && (parmval = parameter_val(att->body->parameter, "format"))){ if(!strucmp(parmval, "flowed")) is_flowed_msg = 1; fs_give((void **) &parmval); if(is_flowed_msg){ if((parmval = parameter_val(att->body->parameter, "delsp")) != NULL){ if(!strucmp(parmval, "yes")) is_delsp_yes = 1; fs_give((void **) &parmval); } } } if(!ps_global->pass_ctrl_chars){ filters[filtcnt++].filter = gf_escape_filter; filters[filtcnt].filter = gf_control_filter; filt_only_c0 = 1; filters[filtcnt++].data = gf_control_filter_opt(&filt_only_c0); } if(flags & FM_DISPLAY) filters[filtcnt++].filter = gf_tag_filter; /* * if it's just plain old text, look for url's */ if(!(att->body->subtype && strucmp(att->body->subtype, "plain"))){ struct variable *vars = ps_global->vars; if((F_ON(F_VIEW_SEL_URL, ps_global) || F_ON(F_VIEW_SEL_URL_HOST, ps_global) || F_ON(F_SCAN_ADDR, ps_global)) && handlesp){ /* * The url_hilite filter really ought to come * after flowing, because flowing with the DelSp=yes parameter * can reassemble broken urls back into identifiable urls. * We add the preflow filter to do only the reassembly part * of the flowing so that we can spot the urls. * At this time (2005-03-29) we know that Apple Mail does * send mail like this sometimes. This filter removes the * sequence SP CRLF if that seems safe. */ if(ps_global->full_header != 2 && is_delsp_yes) filters[filtcnt++].filter = gf_preflow; filters[filtcnt].filter = gf_line_test; filters[filtcnt++].data = gf_line_test_opt(url_hilite, gf_url_hilite_opt(&uh,handlesp,0)); } if((flags & FM_DISPLAY) && !(flags & FM_NOCOLOR) && pico_usingcolor() && VAR_SPECIAL_TEXT_FORE_COLOR && VAR_SPECIAL_TEXT_BACK_COLOR){ filters[filtcnt].filter = gf_line_test; filters[filtcnt++].data = gf_line_test_opt(color_this_text, NULL); } /* * First, paint the signature. * Disclaimers noted below for coloring quotes apply here as well. */ if((flags & FM_DISPLAY) && !(flags & FM_NOCOLOR) && pico_usingcolor() && VAR_SIGNATURE_FORE_COLOR && VAR_SIGNATURE_BACK_COLOR){ filters[filtcnt].filter = gf_quote_test; filters[filtcnt++].data = gf_line_test_opt(color_signature, &is_in_sig); } /* * Gotta be careful with this. The color_a_quote filter adds color * to the beginning and end of the line. This will break some * line_test-style filters which come after it. For example, if they * are looking for something at the start of a line (like color_a_quote * itself). I guess we could fix that by ignoring tags at the * beginning of the line when doing the search. */ if((flags & FM_DISPLAY) && !(flags & FM_NOCOLOR) && pico_usingcolor() && VAR_QUOTE1_FORE_COLOR && VAR_QUOTE1_BACK_COLOR){ add_me = 0; filters[filtcnt].filter = gf_quote_test; filters[filtcnt++].data = gf_line_test_opt(color_a_quote, &is_flowed_msg); } } else if(!strucmp(att->body->subtype, "richtext")){ int plain_opt; plain_opt = !(flags&FM_DISPLAY); /* maybe strip everything! */ filters[filtcnt].filter = gf_rich2plain; filters[filtcnt++].data = gf_rich2plain_opt(&plain_opt); /* width to use for file or printer */ if(wrapit - 5 > 0) wrapit -= 5; } else if(!strucmp(att->body->subtype, "enriched")){ int plain_opt; plain_opt = !(flags&FM_DISPLAY); filters[filtcnt].filter = gf_enriched2plain; filters[filtcnt++].data = gf_enriched2plain_opt(&plain_opt); /* width to use for file or printer */ if(wrapit - 5 > 0) wrapit -= 5; } else if(!strucmp(att->body->subtype, "html") && ps_global->full_header < 2){ /*BUG: sniff the params for "version=2.0" ala draft-ietf-html-spec-01 */ int opts = 0; clear_html_risk(); if(flags & FM_DISPLAY){ gf_io_t warn_pc; if(handlesp){ /* pass on handles awareness */ opts |= GFHP_HANDLES; if(F_OFF(F_QUELL_HOST_AFTER_URL, ps_global) && !(flags & FM_HIDESERVER)) opts |= GFHP_SHOW_SERVER; } if(!(flags & FM_NOEDITORIAL)){ warn_so = so_get(CharStar, NULL, EDIT_ACCESS); gf_set_so_writec(&warn_pc, warn_so); format_editorial(HTML_WARNING, column, flags, handlesp, warn_pc); gf_clear_so_writec(warn_so); so_puts(warn_so, "\015\012"); so_writec('\0', warn_so); } } else opts |= GFHP_STRIPPED; /* don't embed anything! */ if(flags & FM_NOHTMLREL) opts |= GFHP_NO_RELATIVE; if(flags & FM_HTMLRELATED) opts |= GFHP_RELATED_CONTENT; if(flags & FM_HTML) opts |= GFHP_HTML; if(flags & FM_HTMLIMAGES) opts |= GFHP_HTML_IMAGES; wrapit = 0; /* wrap already handled! */ filters[filtcnt].filter = gf_html2plain; filters[filtcnt++].data = gf_html2plain_opt(NULL, column, (flags & (FM_NOINDENT | FM_HTML)) ? 0 : format_view_margin(), handlesp, set_html_risk, opts); if(warn_so){ filters[filtcnt].filter = gf_prepend_editorial; filters[filtcnt++].data = gf_prepend_editorial_opt(get_html_risk, (char *) so_text(warn_so)); } } if (add_me){ filters[filtcnt].filter = gf_quote_test; filters[filtcnt++].data = gf_line_test_opt(select_quote, &doraw); } /* * If the message is not flowed, we do the quote suppression before * the wrapping, because the wrapping does not preserve the quote * characters at the beginnings of the lines in that case. * Otherwise, we defer until after the wrapping. * * Also, this is a good place to do quote-replacement on nonflowed * messages because no other filters depend on the "> ". * Quote-replacement is easier in the flowed case and occurs * automatically in the flowed wrapping filter. */ if(!is_flowed_msg && ps_global->full_header == 0 && !(att->body->subtype && strucmp(att->body->subtype, "plain")) && (flags & FM_DISPLAY)){ if(ps_global->quote_suppression_threshold != 0){ memset(&dq, 0, sizeof(dq)); dq.lines = ps_global->quote_suppression_threshold; dq.is_flowed = is_flowed_msg; dq.indent_length = 0; /* indent didn't happen yet */ dq.saved_line = &free_this; dq.handlesp = handlesp; dq.do_color = (!(flags & FM_NOCOLOR) && pico_usingcolor()); filters[filtcnt].filter = gf_quote_test; filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq); } if(ps_global->VAR_QUOTE_REPLACE_STRING && F_ON(F_QUOTE_REPLACE_NOFLOW, ps_global)){ filters[filtcnt].filter = gf_line_test; filters[filtcnt++].data = gf_line_test_opt(replace_quotes, NULL); } } if(wrapit && !(flags & FM_NOWRAP)){ int wrapflags = (flags & FM_DISPLAY) ? (GFW_HANDLES|GFW_SOFTHYPHEN) : GFW_NONE; if(flags & FM_DISPLAY && !(flags & FM_NOCOLOR) && pico_usingcolor()) wrapflags |= GFW_USECOLOR; /* text/flowed (RFC 2646 + draft)? */ if(ps_global->full_header != 2 && is_flowed_msg){ wrapflags |= GFW_FLOWED; if(is_delsp_yes) wrapflags |= GFW_DELSP; } filters[filtcnt].filter = gf_wrap; filters[filtcnt++].data = gf_wrap_filter_opt(wrapit, column, (flags & FM_NOINDENT) ? 0 : format_view_margin(), 0, wrapflags); } /* * This has to come after wrapping has happened because the user tells * us how many quoted lines to display, and we want that number to be * the wrapped lines, not the pre-wrapped lines. We do it before the * wrapping if the message is not flowed, because the wrapping does not * preserve the quote characters at the beginnings of the lines in that * case. */ if(is_flowed_msg && ps_global->full_header == 0 && !(att->body->subtype && strucmp(att->body->subtype, "plain")) && (flags & FM_DISPLAY) && ps_global->quote_suppression_threshold != 0){ memset(&dq, 0, sizeof(dq)); dq.lines = ps_global->quote_suppression_threshold; dq.is_flowed = is_flowed_msg; dq.indent_length = (wrapit && !(flags & FM_NOWRAP) && !(flags & FM_NOINDENT)) ? format_view_margin()[0] : 0; dq.saved_line = &free_this; dq.handlesp = handlesp; dq.do_color = (!(flags & FM_NOCOLOR) && pico_usingcolor()); filters[filtcnt].filter = gf_quote_test; filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq); } if(charset){ if(F_OFF(F_QUELL_CHARSET_WARNING, ps_global) && !(flags & FM_NOEDITORIAL)){ int rv = TRUE; CONV_TABLE *ct = NULL; /* * Need editorial if message charset is not ascii * and the display charset is not either the same * as the message charset or UTF-8. */ if(strucmp(charset, "us-ascii") && !((ps_global->display_charmap && !strucmp(charset, ps_global->display_charmap)) || !strucmp("UTF-8", ps_global->display_charmap))){ /* * This is probably overkill. We're just using this * conversion_table routine to get at the quality. */ if(ps_global->display_charmap) ct = conversion_table(charset, ps_global->display_charmap); rv = charset_editorial(charset, msgno, handlesp, flags, ct ? ct->quality : CV_NO_TRANSLATE_POSSIBLE, column, pc); } if(!rv) goto write_error; } fs_give((void **) &charset); } /* Format editorial comment about unknown encoding */ if(att->body->encoding > ENCQUOTEDPRINTABLE){ char buf[2048]; snprintf(buf, sizeof(buf), ENCODING_DISCLAIMER, body_encodings[att->body->encoding]); if(!(format_editorial(buf, column, flags, handlesp, pc) == NULL && gf_puts(NEWLINE, pc) && gf_puts(NEWLINE, pc))) goto write_error; } err = detach(ps_global->mail_stream, msgno, att->number, 0L, NULL, pc, filtcnt ? filters : NULL, 0); delete_unused_handles(handlesp); if(free_this) fs_give((void **) &free_this); if(warn_so) so_give(&warn_so); if(err) { error_found++; if(style == QStatus) { q_status_message1(SM_ORDER, 3, 4, "%.200s", err); } else if(style == InLine) { char buftmp[MAILTMPLEN]; snprintf(buftmp, sizeof(buftmp), "%s", att->body->description ? att->body->description : ""); snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s [Error: %s] %c%s%c%s%s", NEWLINE, err, att->body->description ? '\"' : ' ', att->body->description ? buftmp : "", att->body->description ? '\"' : ' ', NEWLINE, NEWLINE); if(!gf_puts(tmp_20k_buf, pc)) goto write_error; } } if(att->body->subtype && (!strucmp(att->body->subtype, "richtext") || !strucmp(att->body->subtype, "enriched")) && !(flags & FM_DISPLAY)){ if(!gf_puts(NEWLINE, pc) || !gf_puts(NEWLINE, pc)) goto write_error; } return(error_found); write_error: if(style == QStatus) q_status_message1(SM_ORDER, 3, 4, "Error writing message: %.200s", error_description(errno)); return(1); }
/* * Parse format_str and fill in disp_form structure based on what's there. * * Args: format_str -- The format string from pinerc. * disp_form -- This is where we fill in the answer. * * The format string consists of special tokens which give the order of * the columns to be displayed. The possible tokens are NICKNAME, * FULLNAME, ADDRESS, FCC, COMMENT. If a token is followed by * parens with an integer inside (FULLNAME(16)) then that means we * make that variable that many characters wide. If it is a percentage, we * allocate that percentage of the columns to that variable. If no * parens, that means we calculate it for the user. The tokens are * delimited by white space. A token of DEFAULT means to calculate the * whole thing as we would if no spec was given. This makes it possible * to specify default for one addrbook and something special for another. */ void parse_format(char *format_str, COL_S *disp_form) { int column = 0; char *p, *q; struct parse_tokens *pt; int nicknames, fullnames, addresses, not_allauto; int warnings = 0; p = format_str; while(p && *p && column < NFIELDS){ p = skip_white_space(p); /* space for next word */ /* look for the ptoken this word matches */ for(pt = ptokens; pt->name; pt++) if(!struncmp(pt->name, p, strlen(pt->name))) break; /* ignore unrecognized word */ if(!pt->name){ char *r; if((r=strindex(p, SPACE)) != NULL) *r = '\0'; dprint((2, "parse_format: ignoring unrecognized word \"%s\" in address-book-formats\n", p ? p : "?")); q_status_message1(SM_ORDER, warnings++==0 ? 1 : 0, 4, /* TRANSLATORS: an informative error message */ _("Ignoring unrecognized word \"%s\" in Address-Book-Formats"), p); /* put back space */ if(r) *r = SPACE; /* skip unrecognized word */ while(p && *p && !isspace((unsigned char)(*p))) p++; continue; } disp_form[column].type = pt->ctype; /* skip over name and look for parens */ p += strlen(pt->name); if(*p == '('){ p++; q = p; while(p && *p && isdigit((unsigned char)*p)) p++; if(p && *p && *p == ')' && p > q){ disp_form[column].wtype = Fixed; disp_form[column].req_width = atoi(q); } else if(p && *p && *p == '%' && p > q){ disp_form[column].wtype = Percent; disp_form[column].req_width = atoi(q); } else{ disp_form[column].wtype = WeCalculate; if(disp_form[column].type == Nickname) disp_form[column].req_width = 8; else disp_form[column].req_width = 3; } } else{ disp_form[column].wtype = WeCalculate; if(disp_form[column].type == Nickname) disp_form[column].req_width = 8; else disp_form[column].req_width = 3; } if(disp_form[column].type == Def){ /* If any type is DEFAULT, the widths are calculated old way */ assign_default: column = 0; disp_form[column].wtype = AllAuto; disp_form[column++].type = Nickname; disp_form[column].wtype = AllAuto; disp_form[column++].type = Fullname; disp_form[column].wtype = AllAuto; disp_form[column++].type = Addr; /* Fill in rest */ while(column < NFIELDS) disp_form[column++].type = Notused; return; } column++; /* skip text at end of word */ while(p && *p && !isspace((unsigned char)(*p))) p++; } if(column == 0){ q_status_message(SM_ORDER, 0, 4, _("Address-Book-Formats has no recognizable words, using default format")); goto assign_default; } /* Fill in rest */ while(column < NFIELDS) disp_form[column++].type = Notused; /* check to see if user is just re-ordering default fields */ nicknames = 0; fullnames = 0; addresses = 0; not_allauto = 0; for(column = 0; column < NFIELDS; column++){ if(disp_form[column].type != Notused && disp_form[column].wtype != WeCalculate) not_allauto++; switch(disp_form[column].type){ case Nickname: nicknames++; break; case Fullname: fullnames++; break; case Addr: addresses++; break; case Filecopy: case Comment: not_allauto++; break; default: break; } } /* * Special case: if there is no address field specified, we put in * a special field called WhenNoAddrDisplayed, which causes list * entries to be displayable in all cases. */ if(!addresses){ for(column = 0; column < NFIELDS; column++) if(disp_form[column].type == Notused) break; if(column < NFIELDS){ disp_form[column].type = WhenNoAddrDisplayed; disp_form[column].wtype = Special; } } if(nicknames == 1 && fullnames == 1 && addresses == 1 && not_allauto == 0) disp_form[0].wtype = AllAuto; /* set to do default widths */ }