Example #1
0
/*----------------------------------------------------------------------
     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 */
        }
    }
}
Example #2
0
File: print.c Project: nysan/alpine
/*----------------------------------------------------------------------
     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 */
}
Example #3
0
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);
}
Example #4
0
File: print.c Project: nysan/alpine
/*----------------------------------------------------------------------
     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);
}
Example #5
0
/*----------------------------------------------------------------------
      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));
        }
    }
}
Example #6
0
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);
}
Example #7
0
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);
}
Example #8
0
/*
 * 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));
}
Example #9
0
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);
}
Example #10
0
/*----------------------------------------------------------------------
  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);
}
Example #11
0
File: print.c Project: nysan/alpine
/*----------------------------------------------------------------------
       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);
}
Example #12
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 */
}
Example #13
0
/*
 * 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;
        }
    }
}
Example #14
0
/* ----------------------------------------------------------------------
   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
}
Example #15
0
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);
}
Example #16
0
File: text.c Project: mavit/alpine
/*----------------------------------------------------------------------
   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);
}
Example #17
0
/*
 * 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 */
}