Esempio n. 1
0
int
context_config_add(struct pine *ps, CONF_S **cl)
{
    char            *raw_ctxt;
    struct variable *var;
    char           **lval;
    int              count;

    if((raw_ctxt = context_edit_screen(ps, "ADD", NULL, NULL, NULL, NULL)) != NULL){

	/*
	 * If var is non-NULL we add to the end of that var.
	 * If it is NULL, that means we're adding to the current_val, so
	 * we'll have to soak up the default values from there into our
	 * own variable.
	 */
	if((*cl)->var){
	    var = (*cl)->var;
	    lval = LVAL((*cl)->var, ew);
	}
	else{
	    q_status_message(SM_ORDER|SM_DING, 3, 3,
			     "Programmer botch in context_config_add");
	    return(0);
	}

	for(count = 0; lval && lval[count]; count++)
	  ;

	if(!ccs_var_insert(ps, raw_ctxt, var, lval, count)){
	    fs_give((void **)&raw_ctxt);
	    q_status_message(SM_ORDER|SM_DING, 3, 3,
			     _("Error adding new collection"));
	    return(0);
	}

	fs_give((void **)&raw_ctxt);

	(*cl)->d.c.cs->starting_var = var;
	(*cl)->d.c.cs->starting_varmem = count;
	q_status_message(SM_ORDER, 0, 3,
			 _("New collection added.  Use \"$\" to adjust order."));
	return(15);
    }

    ps->mangled_screen = 1;
    return(0);
}
Esempio n. 2
0
File: busy.c Progetto: ctubio/alpine
/*
 * Turn on a busy alarm.
 */
int
busy_cue(char *msg, percent_done_t pc_func, int init_msg)
{
    if(msg && !strncmp("Moving", msg, 6)) {
        strncpy(msg+1, "Moved", 5);
        q_status_message(SM_ORDER, 3, 3, msg+1);
    }

    return(0);
}
Esempio n. 3
0
void
done_busy_cue(void *data)
{
    int space_left, slots_used;

    if(final_message && final_message_pri >= 0){
	char progress[MAX_SCREEN_COLS+1];

	/* 2 is for [] */
	space_left = (ps_global->ttyo ? ps_global->ttyo->screen_cols : 80) - busy_width - 2;
	slots_used = MAX(0, MIN(space_left-3, 10));

	if(percent_done_ptr && slots_used >= 4){
	    int left, right;

	    right = (slots_used - 4)/2;
	    left  = slots_used - 4 - right;
	    snprintf(progress, sizeof(progress), "%s |%*s100%%%*s|",
		     busy_message, left, "", right, "");
	    progress[sizeof(progress)-1] = '\0';
	    q_status_message(SM_ORDER,
			     final_message_pri>=2 ? MAX(final_message_pri,3) : 0,
			     final_message_pri+2, progress);
	}
	else{
	    int padding;

	    padding = MAX(0, MIN(space_left-5, spinners[spinner].width-4));

	    snprintf(progress, sizeof(progress), "%s %*sDONE", busy_message,
		     padding, "");
	    progress[sizeof(progress)-1] = '\0';
	    q_status_message(SM_ORDER,
			     final_message_pri>=2 ? MAX(final_message_pri,3) : 0,
			     final_message_pri+2, progress);
	}
    }

    mark_status_dirty();
}
Esempio n. 4
0
MCAP_CMD_S *
mailcap_build_command(int type, char *subtype, BODY *body,
		      char *tmp_file, int *needsterm, int chk_extension)
{
    MailcapEntry *mc;
    char         *command, *err = NULL;
    MCAP_CMD_S   *mc_cmd = NULL;
    int           sp_handling = 0;

    dprint((5, "- mailcap_build_command -\n"));

    mc = mc_get_command(type, subtype, body, chk_extension, &sp_handling);
    if(!mc){
	q_status_message(SM_ORDER, 3, 4, "Error constructing viewer command");
	dprint((1,
		   "mailcap_build_command: no command string for %s/%s\n",
		   body_type_names(type), subtype ? subtype : "?"));
	return((MCAP_CMD_S *)NULL);
    }

    if(needsterm)
      *needsterm = mc->needsterminal;

    if(sp_handling)
      command = cpystr(mc->command);
    else if(!(command = mc_cmd_bldr(mc->command, type, subtype, body, tmp_file, &err)) && err && *err)
      q_status_message(SM_ORDER, 5, 5, err);

    dprint((5, "built command: %s\n", command ? command : "?"));

    if(command){
	mc_cmd = (MCAP_CMD_S *)fs_get(sizeof(MCAP_CMD_S));
	mc_cmd->command = command;
	mc_cmd->special_handling = sp_handling;
    }
    return(mc_cmd);
}
Esempio n. 5
0
/*----------------------------------------------------------------------
  Actually open the pipe used to write piped data down

   Args: 
   Returns: TRUE if success, otherwise FALSE

  ----*/
PIPE_S *
cmd_pipe_open(char *cmd, char **result, int flags, gf_io_t *pc)
{
    char    err[200];
    PIPE_S *pipe;

    if((pipe = open_system_pipe(cmd, result, NULL, flags, 0,
			       pipe_callback, pipe_report_error)) != NULL)
      gf_set_writec(pc, pipe, 0L, PipeStar, (flags & PIPE_RAW) ? 0 : WRITE_TO_LOCALE);
    else{
	/* TRANSLATORS: The argument is the command name being piped to. */
	snprintf(err, sizeof(err), _("Error opening pipe: %s"), cmd ? cmd : "?");
	q_status_message(SM_ORDER | SM_DING, 3, 3, err) ;
    }

    return(pipe);
}
Esempio n. 6
0
/*
 * Insert into "var", which currently has values "oldvarval", the "newline"
 * at position "insert".
 */
int
ccs_var_insert(struct pine *ps, char *newline, struct variable *var, char **oldvarval, int insert)
{
    int    count, i, offset;
    char **newl, ***alval;

    for(count = 0; oldvarval && oldvarval[count]; count++)
      ;

    if(insert < 0 || insert > count){
	q_status_message(SM_ORDER,3,5, "unexpected problem inserting folder");
	return(0);
    }

    newl = (char **)fs_get((count + 2) * sizeof(char *));
    newl[insert] = cpystr(newline);
    newl[count + 1]   = NULL;
    for(i = offset = 0; oldvarval && oldvarval[i]; i++){
	if(i == insert)
	  offset = 1;

	newl[i + offset] = cpystr(oldvarval[i]);
    }

    alval = ALVAL(var, ew);
    if(alval){
	free_list_array(alval);
	if(newl){
	    for(i = 0; newl[i] ; i++)	/* count elements */
	      ;

	    *alval = (char **) fs_get((i+1) * sizeof(char *));

	    for(i = 0; newl[i] ; i++)
	      (*alval)[i] = cpystr(newl[i]);

	    (*alval)[i]         = NULL;
	}
    }

    free_list_array(&newl);
    return(1);
}
Esempio n. 7
0
File: print.c Progetto: nysan/alpine
/*----------------------------------------------------------------------
     Close printer
  
  If we're piping to a spooler close down the pipe and wait for the process
to finish. If we're sending to an attached printer send the escape sequence.
Also let the user know the result of the print
 ----*/
void
close_printer(void)
{
#ifndef _WINDOWS
    if(trailer){
	if(*trailer)
	  fputs(trailer, ps_global->print->fp);

	fs_give((void **)&trailer);
    }

    if(ps_global->print->fp == stdout) {
	if(ansi_off)
          fputs("\033[4i", stdout);
	else
	  printf("%c", 20); /* aux off for wyse60 */

        fflush(stdout);
	if(F_OFF(F_PRESERVE_START_STOP, ps_global))
	  xonxoff_proc(0);			/* turn off XON/XOFF */

	crlf_proc(0);				/* turn off CF->LF xlantion */
    } else {
	(void) close_system_pipe(&ps_global->print->pipe, NULL, pipe_callback);
	display_output_file(ps_global->print->result, "PRINT", NULL, 1);
	if(ps_global->print && ps_global->print->result)
	  fs_give((void **) &ps_global->print->result);
    }
#else /* _WINDOWS */
    mswin_print_done();
#endif /* _WINDOWS */

    if(ps_global->print)
      fs_give((void **) &ps_global->print);

    q_status_message(SM_ASYNC, 0, 3, "Print command completed");
    display_message('x');
}
Esempio n. 8
0
File: print.c Progetto: 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);
}
Esempio n. 9
0
/*
 * This function does white pages lookups.
 *
 * Args  string -- the string to use in the lookup
 *
 * Returns     NULL -- lookup failed
 *          Address -- A single address is returned if lookup was successfull.
 */
ADDRESS *
wp_lookups(char *string, WP_ERR_S *wp_err, int recursing)
{
    ADDRESS *ret_a = NULL;
    char ebuf[200];
#ifdef	ENABLE_LDAP
    LDAP_SERV_RES_S *free_when_done = NULL;
    LDAPLookupStyle style;
    LDAP_CHOOSE_S *winning_e = NULL;
    LDAP_SERV_S *info = NULL;
    static char *fakedomain = "@";
    char *tmp_a_string;
    int   auwe_rv = 0;

    /*
     * Runtime ldap lookup of addrbook entry.
     */
    if(!strncmp(string, RUN_LDAP, LEN_RL)){
	LDAP_SERV_RES_S *head_of_result_list;

	info = break_up_ldap_server(string+LEN_RL);
        head_of_result_list = ldap_lookup(info, "", NULL, wp_err, 1);

	if(head_of_result_list){
	    if(!wp_exit)
	      auwe_rv = ask_user_which_entry(head_of_result_list, string,
					     &winning_e,
					     wp_err,
					     wp_err->wp_err_occurred
					     ? DisplayIfOne : DisplayIfTwo);

	    if(auwe_rv != -5)
	      free_when_done = head_of_result_list;
	}
	else{
	    wp_err->wp_err_occurred = 1;
	    if(wp_err->error){
		q_status_message(SM_ORDER, 3, 5, wp_err->error);
		display_message('x');
		fs_give((void **)&wp_err->error);
	    }

	    /* try using backup email address */
	    if(info && info->mail && *info->mail){
		tmp_a_string = cpystr(info->mail);
		rfc822_parse_adrlist(&ret_a, tmp_a_string, fakedomain);
		fs_give((void **)&tmp_a_string);

		wp_err->error =
		  cpystr(_("Directory lookup failed, using backup email address"));
	    }
	    else{
		/*
		 * Do this so the awful LDAP: ... string won't show up
		 * in the composer. This shouldn't actually happen in
		 * real life, so we're not too concerned about it. If we
		 * were we'd want to recover the nickname we started with
		 * somehow, or something like that.
		 */
		ret_a = mail_newaddr();
		ret_a->mailbox = cpystr("missing-username");
		wp_err->error = cpystr(_("Directory lookup failed, no backup email address available"));
	    }

	    q_status_message(SM_ORDER, 3, 5, wp_err->error);
	    display_message('x');
	}
    }
    else{
	style = F_ON(F_COMPOSE_REJECTS_UNQUAL, ps_global)
			? DisplayIfOne : DisplayIfTwo;
	auwe_rv = ldap_lookup_all(string, as.n_serv, recursing, style, NULL,
				  &winning_e, wp_err, &free_when_done);
    }

    if(winning_e && auwe_rv != -5){
	ret_a = address_from_ldap(winning_e);

	if(pith_opt_save_ldap_entry && ret_a && F_ON(F_ADD_LDAP_TO_ABOOK, ps_global) && !info)
	  (*pith_opt_save_ldap_entry)(ps_global, winning_e, 1);


	fs_give((void **)&winning_e);
    }

    /* Info's only set in the RUN_LDAP case */
    if(info){
	if(ret_a && ret_a->host){
	    ADDRESS *backup = NULL;

	    if(info->mail && *info->mail)
	      rfc822_parse_adrlist(&backup, info->mail, fakedomain);

	    if(!backup || !address_is_same(ret_a, backup)){
		if(wp_err->error){
		    q_status_message(SM_ORDER, 3, 5, wp_err->error);
		    display_message('x');
		    fs_give((void **)&wp_err->error);
		}

		snprintf(ebuf, sizeof(ebuf),
	       _("Warning: current address different from saved address (%s)"),
		   info->mail);
		wp_err->error = cpystr(ebuf);
		q_status_message(SM_ORDER, 3, 5, wp_err->error);
		display_message('x');
	    }

	    if(backup)
	      mail_free_address(&backup);
	}

	free_ldap_server_info(&info);
    }

    if(free_when_done)
      free_ldap_result_list(&free_when_done);
#endif	/* ENABLE_LDAP */

    if(ret_a){
	if(ret_a->mailbox){  /* indicates there was a MAIL attribute */
	    if(!ret_a->host || !ret_a->host[0]){
		if(ret_a->host)
		  fs_give((void **)&ret_a->host);

		ret_a->host = cpystr("missing-hostname");
		wp_err->wp_err_occurred = 1;
		if(wp_err->error)
		  fs_give((void **)&wp_err->error);

		wp_err->error = cpystr(_("Missing hostname in LDAP address"));
		q_status_message(SM_ORDER, 3, 5, wp_err->error);
		display_message('x');
	    }

	    if(!ret_a->mailbox[0]){
		if(ret_a->mailbox)
		  fs_give((void **)&ret_a->mailbox);

		ret_a->mailbox = cpystr("missing-username");
		wp_err->wp_err_occurred = 1;
		if(wp_err->error)
		  fs_give((void **)&wp_err->error);

		wp_err->error = cpystr(_("Missing username in LDAP address"));
		q_status_message(SM_ORDER, 3, 5, wp_err->error);
		display_message('x');
	    }
	}
	else{
	    wp_err->wp_err_occurred = 1;

	    if(wp_err->error)
	      fs_give((void **)&wp_err->error);

	    snprintf(ebuf, sizeof(ebuf), _("No email address available for \"%s\""),
		    (ret_a->personal && *ret_a->personal)
			    ? ret_a->personal
			    : "selected entry");
	    wp_err->error = cpystr(ebuf);
	    q_status_message(SM_ORDER, 3, 5, wp_err->error);
	    display_message('x');
	    mail_free_address(&ret_a);
	    ret_a = NULL;
	}
    }

    return(ret_a);
}
Esempio n. 10
0
/*
 * Do an LDAP lookup to the server described in the info argument.
 *
 * Args      info -- LDAP info for server.
 *         string -- String to lookup.
 *           cust -- Possible custom filter description.
 *         wp_err -- We set this is we get a white pages error.
 *  name_in_error -- Caller sets this if they want us to include the server
 *                   name in error messages.
 *
 * Returns  Results of lookup, NULL if lookup failed.
 */
LDAP_SERV_RES_S *
ldap_lookup(LDAP_SERV_S *info, char *string, CUSTOM_FILT_S *cust,
	    WP_ERR_S *wp_err, int name_in_error)
{
    char     ebuf[900];
    char     buf[900];
    char    *serv, *base, *serv_errstr;
    char    *mailattr, *snattr, *gnattr, *cnattr;
    int      we_cancel = 0, we_turned_on = 0;
    LDAP_SERV_RES_S *serv_res = NULL;
    LDAP *ld;
    long  pwdtrial = 0L;
    int   ld_errnum;
    char *ld_errstr;


    if(!info)
      return(serv_res);

    serv = cpystr((info->serv && *info->serv) ? info->serv : "?");

    if(name_in_error)
      snprintf(ebuf, sizeof(ebuf), " (%s)",
	      (info->nick && *info->nick) ? info->nick : serv);
    else
      ebuf[0] = '\0';

    serv_errstr = cpystr(ebuf);
    base = cpystr(info->base ? info->base : "");

    if(info->port < 0)
      info->port = LDAP_PORT;

    if(info->type < 0)
      info->type = DEF_LDAP_TYPE;

    if(info->srch < 0)
      info->srch = DEF_LDAP_SRCH;
	
    if(info->time < 0)
      info->time = DEF_LDAP_TIME;

    if(info->size < 0)
      info->size = DEF_LDAP_SIZE;

    if(info->scope < 0)
      info->scope = DEF_LDAP_SCOPE;

    mailattr = (info->mailattr && info->mailattr[0]) ? info->mailattr
						     : DEF_LDAP_MAILATTR;
    snattr = (info->snattr && info->snattr[0]) ? info->snattr
						     : DEF_LDAP_SNATTR;
    gnattr = (info->gnattr && info->gnattr[0]) ? info->gnattr
						     : DEF_LDAP_GNATTR;
    cnattr = (info->cnattr && info->cnattr[0]) ? info->cnattr
						     : DEF_LDAP_CNATTR;

    /*
     * We may want to keep ldap handles open, but at least for
     * now, re-open them every time.
     */

    dprint((3, "ldap_lookup(%s,%d)\n", serv ? serv : "?", info->port));

    snprintf(ebuf, sizeof(ebuf), "Searching%s%s%s on %s",
	    (string && *string) ? " for \"" : "",
	    (string && *string) ? string : "",
	    (string && *string) ? "\"" : "",
	    serv);
    we_turned_on = intr_handling_on();		/* this erases keymenu */
    we_cancel = busy_cue(ebuf, NULL, 0);
    if(wp_err->mangled)
      *(wp_err->mangled) = 1;

#ifdef _SOLARIS_SDK
    if(info->tls || info->tlsmust)
      ldapssl_client_init(NULL, NULL);
    if((ld = ldap_init(serv, info->port)) == NULL)
#else
#if (LDAPAPI >= 11)
    if((ld = ldap_init(serv, info->port)) == NULL)
#else
    if((ld = ldap_open(serv, info->port)) == NULL)
#endif
#endif
    {
      /* TRANSLATORS: All of the three args together are an error message */
      snprintf(ebuf, sizeof(ebuf), _("Access to LDAP server failed: %s%s(%s)"),
	      errno ? error_description(errno) : "",
	      errno ? " " : "",
	      serv);
      wp_err->wp_err_occurred = 1;
      if(wp_err->error)
	fs_give((void **)&wp_err->error);

      wp_err->error = cpystr(ebuf);
      if(we_cancel)
        cancel_busy_cue(-1);

      q_status_message(SM_ORDER, 3, 5, wp_err->error);
      display_message('x');
      dprint((2, "%s\n", ebuf));
    }
    else if(!ps_global->intr_pending){
      int proto = 3, tlsmustbail = 0;
      char pwd[NETMAXPASSWD], user[NETMAXUSER];
      char *passwd = NULL;
      char hostbuf[1024];
      NETMBX mb;
#ifndef _WINDOWS
      int rc;
#endif

      memset(&mb, 0, sizeof(mb));

#ifdef _SOLARIS_SDK
      if(info->tls || info->tlsmust)
	rc = ldapssl_install_routines(ld);
#endif

      if(ldap_v3_is_supported(ld) &&
	 our_ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &proto) == 0){
	dprint((5, "ldap: using version 3 protocol\n"));
      }

      /*
       * If we don't set RESTART then the select() waiting for the answer
       * in libldap will be interrupted and stopped by our busy_cue.
       */
      our_ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON);

      /*
       * If we need to authenticate, get the password. We are not
       * supporting SASL authentication, just LDAP simple.
       */
      if(info->binddn && info->binddn[0]){
	  char pmt[500];
	  char *space;

	  snprintf(hostbuf, sizeof(hostbuf), "{%s}dummy", info->serv ? info->serv : "?");

	  /*
	   * We don't handle multiple space-delimited hosts well.
	   * We don't know which we're asking for a password for.
	   * We're not connected yet so we can't know.
	   */
	  if((space=strindex(hostbuf, ' ')) != NULL)
	    *space = '\0';

	  mail_valid_net_parse_work(hostbuf, &mb, "ldap");
	  mb.port = info->port;
	  mb.tlsflag = (info->tls || info->tlsmust) ? 1 : 0;

try_password_again:

	  if(mb.tlsflag
	     && (pwdtrial > 0 || 
#ifndef _WINDOWS
#ifdef _SOLARIS_SDK
		 (rc == LDAP_SUCCESS)
#else /* !_SOLARIS_SDK */
		 ((rc=ldap_start_tls_s(ld, NULL, NULL)) == LDAP_SUCCESS)
#endif /* !_SOLARIS_SDK */
#else /* _WINDOWS */
		 0  /* TODO: find a way to do this in Windows */
#endif /* _WINDOWS */
		 ))
	    mb.tlsflag = 1;
	  else
	    mb.tlsflag = 0;

	  if((info->tls || info->tlsmust) && !mb.tlsflag){
	    q_status_message(SM_ORDER, 3, 5, "Not able to start TLS encryption for LDAP server");
	    if(info->tlsmust)
	      tlsmustbail++;
	  }

	  if(!tlsmustbail){
	      snprintf(pmt, sizeof(pmt), "  %s", (info->nick && *info->nick) ? info->nick : serv);
	      mm_login_work(&mb, user, pwd, pwdtrial, pmt, info->binddn);
	      if(pwd && pwd[0])
		passwd = pwd;
	  }
      }


      /*
       * LDAPv2 requires the bind. v3 doesn't require it but we want
       * to tell the server we're v3 if the server supports v3, and if the
       * server doesn't support v3 the bind is required.
       */
      if(tlsmustbail || ldap_simple_bind_s(ld, info->binddn, passwd) != LDAP_SUCCESS){
	wp_err->wp_err_occurred = 1;

	ld_errnum = our_ldap_get_lderrno(ld, NULL, &ld_errstr);

        if(!tlsmustbail && info->binddn && info->binddn[0] && pwdtrial < 2L
	   && ld_errnum == LDAP_INVALID_CREDENTIALS){
	  pwdtrial++;
          q_status_message(SM_ORDER, 3, 5, _("Invalid password"));
	  goto try_password_again;
	}

	snprintf(ebuf, sizeof(ebuf), _("LDAP server failed: %s%s%s%s"),
		ldap_err2string(ld_errnum),
		serv_errstr,
		(ld_errstr && *ld_errstr) ? ": " : "",
		(ld_errstr && *ld_errstr) ? ld_errstr : "");

        if(wp_err->error)
	  fs_give((void **)&wp_err->error);

        if(we_cancel)
          cancel_busy_cue(-1);

	ldap_unbind(ld);
        wp_err->error = cpystr(ebuf);
        q_status_message(SM_ORDER, 3, 5, wp_err->error);
        display_message('x');
	dprint((2, "%s\n", ebuf));
      }
      else if(!ps_global->intr_pending){
	int          srch_res, args, slen, flen;
#define TEMPLATELEN 512
	char         filt_template[TEMPLATELEN + 1];
	char         filt_format[2*TEMPLATELEN + 1];
	char         filter[2*TEMPLATELEN + 1];
	char         scp[2*TEMPLATELEN + 1];
	char        *p, *q;
	LDAPMessage *res = NULL;
	int intr_happened = 0;
	int tl;

	tl = (info->time == 0) ? info->time : info->time + 10;

	our_ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &tl);
	our_ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &info->size);

	/*
	 * If a custom filter has been passed in and it doesn't include a
	 * request to combine it with the configured filter, then replace
	 * any configured filter with the passed in filter.
	 */
	if(cust && cust->filt && !cust->combine){
	    if(info->cust)
	      fs_give((void **)&info->cust);
	    
	    info->cust = cpystr(cust->filt);
	}

	if(info->cust && *info->cust){	/* use custom filter if present */
	    strncpy(filt_template, info->cust, sizeof(filt_template));
	    filt_template[sizeof(filt_template)-1] = '\0';
	}
	else{				/* else use configured filter */
	    switch(info->type){
	      case LDAP_TYPE_SUR:
		snprintf(filt_template, sizeof(filt_template), "(%s=%%s)", snattr);
		break;
	      case LDAP_TYPE_GIVEN:
		snprintf(filt_template, sizeof(filt_template), "(%s=%%s)", gnattr);
		break;
	      case LDAP_TYPE_EMAIL:
		snprintf(filt_template, sizeof(filt_template), "(%s=%%s)", mailattr);
		break;
	      case LDAP_TYPE_CN_EMAIL:
		snprintf(filt_template, sizeof(filt_template), "(|(%s=%%s)(%s=%%s))", cnattr,
			mailattr);
		break;
	      case LDAP_TYPE_SUR_GIVEN:
		snprintf(filt_template, sizeof(filt_template), "(|(%s=%%s)(%s=%%s))",
			snattr, gnattr);
		break;
	      case LDAP_TYPE_SEVERAL:
		snprintf(filt_template, sizeof(filt_template),
			"(|(%s=%%s)(%s=%%s)(%s=%%s)(%s=%%s))",
			cnattr, mailattr, snattr, gnattr);
		break;
	      default:
	      case LDAP_TYPE_CN:
		snprintf(filt_template, sizeof(filt_template), "(%s=%%s)", cnattr);
		break;
	    }
	}

	/* just copy if custom */
	if(info->cust && *info->cust)
	  info->srch = LDAP_SRCH_EQUALS;

	p = filt_template;
	q = filt_format;
	memset((void *)filt_format, 0, sizeof(filt_format));
	args = 0;
	while(*p && (q - filt_format) + 4 < sizeof(filt_format)){
	    if(*p == '%' && *(p+1) == 's'){
		args++;
		switch(info->srch){
		  /* Exact match */
		  case LDAP_SRCH_EQUALS:
		    *q++ = *p++;
		    *q++ = *p++;
		    break;

		  /* Append wildcard after %s */
		  case LDAP_SRCH_BEGINS:
		    *q++ = *p++;
		    *q++ = *p++;
		    *q++ = '*';
		    break;

		  /* Insert wildcard before %s */
		  case LDAP_SRCH_ENDS:
		    *q++ = '*';
		    *q++ = *p++;
		    *q++ = *p++;
		    break;

		  /* Put wildcard before and after %s */
		  default:
		  case LDAP_SRCH_CONTAINS:
		    *q++ = '*';
		    *q++ = *p++;
		    *q++ = *p++;
		    *q++ = '*';
		    break;
		}
	    }
	    else
	      *q++ = *p++;
	}

	if(q - filt_format < sizeof(filt_format))
	  *q = '\0';

	filt_format[sizeof(filt_format)-1] = '\0';

	/*
	 * If combine is lit we put the custom filter and the filt_format
	 * filter and combine them with an &.
	 */
	if(cust && cust->filt && cust->combine){
	    char *combined;
	    size_t l;

	    l = strlen(filt_format) + strlen(cust->filt) + 3;
	    combined = (char *) fs_get((l+1) * sizeof(char));
	    snprintf(combined, l+1, "(&%s%s)", cust->filt, filt_format);
	    strncpy(filt_format, combined, sizeof(filt_format));
	    filt_format[sizeof(filt_format)-1] = '\0';
	    fs_give((void **) &combined);
	}

	/*
	 * Ad hoc attempt to make "Steve Hubert" match
	 * Steven Hubert but not Steven Shubert.
	 * We replace a <SPACE> with * <SPACE> (not * <SPACE> *).
	 */
	memset((void *)scp, 0, sizeof(scp));
	if(info->nosub)
	  strncpy(scp, string, sizeof(scp));
	else{
	    p = string;
	    q = scp;
	    while(*p && (q - scp) + 1 < sizeof(scp)){
		if(*p == SPACE && *(p+1) != SPACE){
		    *q++ = '*';
		    *q++ = *p++;
		}
		else
		  *q++ = *p++;
	    }
	}

	scp[sizeof(scp)-1] = '\0';

	slen = strlen(scp);
	flen = strlen(filt_format);
	/* truncate string if it will overflow filter */
	if(args*slen + flen - 2*args > sizeof(filter)-1)
	  scp[(sizeof(filter)-1 - flen)/args] = '\0';

	/*
	 * Replace %s's with scp.
	 */
	switch(args){
	  case 0:
	    snprintf(filter, sizeof(filter), "%s", filt_format);
	    break;
	  case 1:
	    snprintf(filter, sizeof(filter), filt_format, scp);
	    break;
	  case 2:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp);
	    break;
	  case 3:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp);
	    break;
	  case 4:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp);
	    break;
	  case 5:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp);
	    break;
	  case 6:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp, scp);
	    break;
	  case 7:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp, scp, scp);
	    break;
	  case 8:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp, scp, scp,
		    scp);
	    break;
	  case 9:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp, scp, scp,
		    scp, scp);
	    break;
	  case 10:
	  default:
	    snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp, scp, scp,
		    scp, scp, scp);
	    break;
	}

	/* replace double *'s with single *'s in filter */
	for(p = q = filter; *p; p++)
	  if(*p != '*' || p == filter || *(p-1) != '*')
	    *q++ = *p;

	*q = '\0';

	(void) removing_double_quotes(base);
	dprint((5, "about to ldap_search(\"%s\", %s)\n",
	       base ? base : "?", filter ? filter : "?"));
        if(ps_global->intr_pending)
	  srch_res = LDAP_PROTOCOL_ERROR;
	else{
	  int msgid;
	  time_t start_time;

	  start_time = time((time_t *)0);

	  dprint((6, "ldap_lookup: calling ldap_search\n"));
	  msgid = ldap_search(ld, base, info->scope, filter, NULL, 0);

	  if(msgid == -1)
	    srch_res = our_ldap_get_lderrno(ld, NULL, NULL);
	  else{
	    int lres;
	    /*
	     * Warning: struct timeval is not portable. However, since it is
	     * part of LDAP api it must be portable to all platforms LDAP
	     * has been ported to.
	     */
	    struct timeval t;

	    t.tv_sec  = 1; t.tv_usec = 0;
	      
	    do {
	      if(ps_global->intr_pending)
		intr_happened = 1;

	      dprint((6, "ldap_result(id=%d): ", msgid));
	      if((lres=ldap_result(ld, msgid, LDAP_MSG_ALL, &t, &res)) == -1){
	        /* error */
		srch_res = our_ldap_get_lderrno(ld, NULL, NULL);
	        dprint((6, "error (-1 returned): ld_errno=%d\n",
			   srch_res));
	      }
	      else if(lres == 0){  /* timeout, no results available */
		if(intr_happened){
		  ldap_abandon(ld, msgid);
		  srch_res = LDAP_PROTOCOL_ERROR;
		  if(our_ldap_get_lderrno(ld, NULL, NULL) == LDAP_SUCCESS)
		    our_ldap_set_lderrno(ld, LDAP_PROTOCOL_ERROR, NULL, NULL);

	          dprint((6, "timeout, intr: srch_res=%d\n",
			     srch_res));
		}
		else if(info->time > 0 &&
			((long)time((time_t *)0) - start_time) > info->time){
		  /* try for partial results */
		  t.tv_sec  = 0; t.tv_usec = 0;
		  lres = ldap_result(ld, msgid, LDAP_MSG_RECEIVED, &t, &res);
		  if(lres > 0 && lres != LDAP_RES_SEARCH_RESULT){
		    srch_res = LDAP_SUCCESS;
		    dprint((6, "partial result: lres=0x%x\n", lres));
		  }
		  else{
		    if(lres == 0)
		      ldap_abandon(ld, msgid);

		    srch_res = LDAP_TIMEOUT;
		    if(our_ldap_get_lderrno(ld, NULL, NULL) == LDAP_SUCCESS)
		      our_ldap_set_lderrno(ld, LDAP_TIMEOUT, NULL, NULL);

	            dprint((6,
			       "timeout, total_time (%d), srch_res=%d\n",
			       info->time, srch_res));
		  }
		}
		else{
	          dprint((6, "timeout\n"));
		}
	      }
	      else{
		srch_res = ldap_result2error(ld, res, 0);
	        dprint((6, "lres=0x%x, srch_res=%d\n", lres,
			   srch_res));
	      }
	    }while(lres == 0 &&
		    !(intr_happened ||
		      (info->time > 0 &&
		       ((long)time((time_t *)0) - start_time) > info->time)));
	  }
	}

	if(intr_happened){
	  wp_exit = 1;
          if(we_cancel)
            cancel_busy_cue(-1);

	  if(wp_err->error)
	    fs_give((void **)&wp_err->error);
	  else{
	    q_status_message(SM_ORDER, 0, 1, "Interrupt");
	    display_message('x');
	    fflush(stdout);
	  }

	  if(res)
	    ldap_msgfree(res);
	  if(ld)
	    ldap_unbind(ld);
	  
	  res = NULL; ld  = NULL;
	}
	else if(srch_res != LDAP_SUCCESS &&
	   srch_res != LDAP_TIMELIMIT_EXCEEDED &&
	   srch_res != LDAP_RESULTS_TOO_LARGE &&
	   srch_res != LDAP_TIMEOUT &&
	   srch_res != LDAP_SIZELIMIT_EXCEEDED){
	  wp_err->wp_err_occurred = 1;

	  ld_errnum = our_ldap_get_lderrno(ld, NULL, &ld_errstr);

	  snprintf(ebuf, sizeof(ebuf), _("LDAP search failed: %s%s%s%s"),
		  ldap_err2string(ld_errnum),
		  serv_errstr,
		  (ld_errstr && *ld_errstr) ? ": " : "",
		  (ld_errstr && *ld_errstr) ? ld_errstr : "");

          if(wp_err->error)
	    fs_give((void **)&wp_err->error);

          wp_err->error = cpystr(ebuf);
          if(we_cancel)
            cancel_busy_cue(-1);

          q_status_message(SM_ORDER, 3, 5, wp_err->error);
          display_message('x');
	  dprint((2, "%s\n", ebuf));
	  if(res)
	    ldap_msgfree(res);
	  if(ld)
	    ldap_unbind(ld);
	  
	  res = NULL; ld  = NULL;
	}
	else{
	  int cnt;

	  cnt = ldap_count_entries(ld, res);

	  if(cnt > 0){

	    if(srch_res == LDAP_TIMELIMIT_EXCEEDED ||
	       srch_res == LDAP_RESULTS_TOO_LARGE ||
	       srch_res == LDAP_TIMEOUT ||
	       srch_res == LDAP_SIZELIMIT_EXCEEDED){
	      wp_err->wp_err_occurred = 1;
	      ld_errnum = our_ldap_get_lderrno(ld, NULL, &ld_errstr);

	      snprintf(ebuf, sizeof(ebuf), _("LDAP partial results: %s%s%s%s"),
		      ldap_err2string(ld_errnum),
		      serv_errstr,
		      (ld_errstr && *ld_errstr) ? ": " : "",
		      (ld_errstr && *ld_errstr) ? ld_errstr : "");
	      dprint((2, "%s\n", ebuf));
	      if(wp_err->error)
		fs_give((void **)&wp_err->error);

	      wp_err->error = cpystr(ebuf);
	      if(we_cancel)
		cancel_busy_cue(-1);

	      q_status_message(SM_ORDER, 3, 5, wp_err->error);
	      display_message('x');
	    }

	    dprint((5, "Matched %d entries on %s\n",
	           cnt, serv ? serv : "?"));

	    serv_res = (LDAP_SERV_RES_S *)fs_get(sizeof(LDAP_SERV_RES_S));
	    memset((void *)serv_res, 0, sizeof(*serv_res));
	    serv_res->ld   = ld;
	    serv_res->res  = res;
	    serv_res->info_used = copy_ldap_serv_info(info);
	    /* Save by reference? */
	    if(info->ref){
		snprintf(buf, sizeof(buf), "%s:%s", serv, comatose(info->port));
		serv_res->serv = cpystr(buf);
	    }
	    else
	      serv_res->serv = NULL;

	    serv_res->next = NULL;
	  }
	  else{
	    if(srch_res == LDAP_TIMELIMIT_EXCEEDED ||
	       srch_res == LDAP_RESULTS_TOO_LARGE ||
	       srch_res == LDAP_TIMEOUT ||
	       srch_res == LDAP_SIZELIMIT_EXCEEDED){
	      wp_err->wp_err_occurred = 1;
	      wp_err->ldap_errno      = srch_res;

	      ld_errnum = our_ldap_get_lderrno(ld, NULL, &ld_errstr);

	      snprintf(ebuf, sizeof(ebuf), _("LDAP search failed: %s%s%s%s"),
		      ldap_err2string(ld_errnum),
		      serv_errstr,
		      (ld_errstr && *ld_errstr) ? ": " : "",
		      (ld_errstr && *ld_errstr) ? ld_errstr : "");

	      if(wp_err->error)
		fs_give((void **)&wp_err->error);

	      wp_err->error = cpystr(ebuf);
	      if(we_cancel)
		cancel_busy_cue(-1);

	      q_status_message(SM_ORDER, 3, 5, wp_err->error);
	      display_message('x');
	      dprint((2, "%s\n", ebuf));
	    }

	    dprint((5, "Matched 0 entries on %s\n",
		   serv ? serv : "?"));
	    if(res)
	      ldap_msgfree(res);
	    if(ld)
	      ldap_unbind(ld);

	    res = NULL; ld  = NULL;
	  }
	}
      }
    }

    if(we_cancel)
      cancel_busy_cue(-1);

    if(we_turned_on)
      intr_handling_off();

    if(serv)
      fs_give((void **)&serv);
    if(base)
      fs_give((void **)&base);
    if(serv_errstr)
      fs_give((void **)&serv_errstr);

    return(serv_res);
}
Esempio n. 11
0
/*----------------------------------------------------------------------
   Function to control flag set/clearing

   Basically, turn the flags into a fake list of features...

   Returns 0 unless user has added a keyword, then 1.

 ----*/
int
flag_maintenance_screen(struct pine *ps, struct flag_screen *flags)
{
    int		  i, lv, lc, maxwidth, offset, need, rv = 0;
    char	  tmp[1200], **p, *spacer;
    CONF_S	 *ctmpa, *first_line;
    struct	  flag_table  *fp;
    OPT_SCREEN_S  screen;

try_again:
    maxwidth = MAX(MIN((ps->ttyo ? ps->ttyo->screen_cols : 80), 150), 30);
    first_line = NULL;
    ctmpa = NULL;

    for(p = flags->explanation; p && *p; p++) {
        new_confline(&ctmpa);
        ctmpa->keymenu   = &flag_keymenu;
        ctmpa->help      = NO_HELP;
        ctmpa->tool      = flag_checkbox_tool;
        ctmpa->flags    |= CF_NOSELECT;
        ctmpa->valoffset = 0;
        ctmpa->value     = cpystr(_(*p));
    }

    /* Now wire flags checkboxes together */
    for(lv = 0, lc = 0, fp = (flags->flag_table ? *flags->flag_table : NULL);
            fp && fp->name; fp++) {	/* longest name */
        if(fp->flag != F_COMMENT) {
            if(lv < (i = utf8_width(_(fp->name))))
                lv = i;
            if(fp->comment && lc < (i = utf8_width(fp->comment)))
                lc = i;
        }
    }

    lv = MIN(lv,100);
    lc = MIN(lc,100);
    if(lc > 0)
        spacer = "    ";
    else
        spacer = "";

    offset = 6;
    if((need = offset + 5 + lv + strlen(spacer) + lc) > maxwidth) {
        offset -= (need - maxwidth);
        offset = MAX(0,offset);
        if((need = offset + 5 + lv + strlen(spacer) + lc) > maxwidth) {
            spacer = " ";
            if((need = offset + 5 + lv + strlen(spacer) + lc) > maxwidth) {
                lc -= (need - maxwidth);
                lc = MAX(0,lc);
                if(lc == 0)
                    spacer = "";
            }
        }
    }

    new_confline(&ctmpa);
    ctmpa->keymenu   = &flag_keymenu;
    ctmpa->help      = NO_HELP;
    ctmpa->tool      = flag_checkbox_tool;
    ctmpa->flags    |= CF_NOSELECT;
    ctmpa->valoffset = 0;
    ctmpa->value     = cpystr("");

    new_confline(&ctmpa);
    ctmpa->keymenu   = &flag_keymenu;
    ctmpa->help      = NO_HELP;
    ctmpa->tool      = flag_checkbox_tool;
    ctmpa->flags    |= CF_NOSELECT;
    ctmpa->valoffset = 0;
    utf8_snprintf(tmp, sizeof(tmp), "%*.*w  %s", offset+3, offset+3, _("Set"), _("Flag/Keyword Name"));
    tmp[sizeof(tmp)-1] = '\0';
    ctmpa->value = cpystr(tmp);

    new_confline(&ctmpa);
    ctmpa->keymenu   = &flag_keymenu;
    ctmpa->help      = NO_HELP;
    ctmpa->tool      = flag_checkbox_tool;
    ctmpa->flags    |= CF_NOSELECT;
    ctmpa->valoffset = 0;
    snprintf(tmp, sizeof(tmp), "%*.*s---  %.*s",
             offset, offset, "",
             lv+lc+strlen(spacer), repeat_char(lv+lc+strlen(spacer), '-'));
    tmp[sizeof(tmp)-1] = '\0';
    ctmpa->value = cpystr(tmp);

    for(fp = (flags->flag_table ? *flags->flag_table : NULL);
            fp && fp->name; fp++) {	/* build the list */
        new_confline(&ctmpa);
        if(!first_line && (fp->flag != F_COMMENT))
            first_line = ctmpa;

        ctmpa->keymenu   = &flag_keymenu;
        ctmpa->tool      = flag_checkbox_tool;
        ctmpa->valoffset = offset;

        if(fp->flag == F_COMMENT) {
            ctmpa->help   = NO_HELP;
            ctmpa->flags |= CF_NOSELECT;
            ctmpa->value  = cpystr(fp->name);
        }
        else {
            ctmpa->help		  = fp->help;
            ctmpa->d.f.ftbl	  = flags->flag_table;
            ctmpa->d.f.fp	  = fp;

            utf8_snprintf(tmp, sizeof(tmp), "[%c]  %-*.*w%s%-*.*w",
                          (fp->set == 0) ? ' ' : (fp->set == 1) ? 'X' : '?',
                          lv, lv, _(fp->name),
                          spacer, lc, lc, fp->comment ? fp->comment : "");
            ctmpa->value = cpystr(tmp);
        }
    }

    memset(&screen, 0, sizeof(screen));
    /*
     * TRANSLATORS: FLAG MAINTENANCE is a screen title.
     * Print something1 using something2.  configuration is something1
     */
    if(conf_scroll_screen(ps, &screen, first_line,
                          _("FLAG MAINTENANCE"),
                          _("configuration"), 0) == FLAG_ADD_RETURN) {
        int flags, r;
        char keyword[500];
        char nickname[500];
        char prompt[500];
        char *error = NULL;
        KEYWORD_S *kw;
        HelpType help;

        /*
         * User is asking to add a new keyword. We will add it to the
         * mailbox if necessary and add it to the keywords list from
         * Setup/Config. Then we will modify the flag_table and present
         * the flag modification screen again.
         */

        ps->mangled_screen = 1;
        keyword[0] = '\0';
        flags = OE_APPEND_CURRENT;
        help = NO_HELP;

        do {
            if(error) {
                q_status_message(SM_ORDER, 3, 4, error);
                fs_give((void **) &error);
            }

            strncpy(prompt, _("Keyword to be added : "), sizeof(prompt)-1);
            prompt[sizeof(prompt)-1] = '\0';
            r = optionally_enter(keyword, -FOOTER_ROWS(ps_global), 0,
                                 sizeof(keyword), prompt, NULL, help, &flags);

            if(r == 3)
                help = help == NO_HELP ? h_type_keyword : NO_HELP;
            else if(r == 1) {
                cmd_cancelled("Add Keyword");
                goto try_again;
            }

            removing_leading_and_trailing_white_space(keyword);

        } while(r == 3 || keyword_check(keyword, &error));

        for(kw = ps->keywords; kw; kw = kw->next) {
            if(kw->kw && !strucmp(kw->kw, keyword)) {
                q_status_message(SM_ORDER, 3, 4, _("Keyword already configured, changing nickname"));
                break;
            }
        }

        snprintf(prompt, sizeof(prompt), _("Optional nickname for \"%s\" : "), keyword);

        nickname[0] = '\0';
        help = NO_HELP;

        do {
            r = optionally_enter(nickname, -FOOTER_ROWS(ps_global), 0,
                                 sizeof(nickname), prompt, NULL, help, &flags);

            if(r == 3)
                help = help == NO_HELP ? h_type_keyword_nickname : NO_HELP;
            else if(r == 1) {
                cmd_cancelled("Add Keyword");
                goto try_again;
            }

            removing_leading_and_trailing_white_space(nickname);

        } while(r == 3);

        if(keyword[0]) {
            char ***alval;
            int offset = -1;
            struct variable *var;

            var = &ps_global->vars[V_KEYWORDS];
            alval = ALVAL(var, Main);

            for(kw = ps->keywords; kw; kw = kw->next) {
                offset++;
                if(kw->kw && !strucmp(kw->kw, keyword)) {
                    /* looks like it should already exist at offset */
                    break;
                }
            }

            if(!kw)
                offset = -1;

            if(offset >= 0 && (*alval) && (*alval)[offset]) {
                fs_give((void **) &(*alval)[offset]);
                (*alval)[offset] = put_pair(nickname, keyword);
            }
            else if(!*alval) {
                offset = 0;
                *alval = (char **) fs_get(2*sizeof(char *));
                (*alval)[offset] = put_pair(nickname, keyword);
                (*alval)[offset+1] = NULL;
            }
            else {
                for(offset=0; (*alval)[offset]; offset++);
                ;

                fs_resize((void **) alval, (offset + 2) * sizeof(char *));
                (*alval)[offset] = put_pair(nickname, keyword);
                (*alval)[offset+1] = NULL;
            }

            set_current_val(var, TRUE, FALSE);
            if(ps_global->prc)
                ps_global->prc->outstanding_pinerc_changes = 1;

            if(ps_global->keywords)
                free_keyword_list(&ps_global->keywords);

            if(var->current_val.l && var->current_val.l[0])
                ps_global->keywords = init_keyword_list(var->current_val.l);

            clear_index_cache(ps_global->mail_stream, 0);

            rv = 1;
        }
    }

    ps->mangled_screen = 1;

    return(rv);
}
Esempio n. 12
0
void
pipe_report_error(char *errormsg)
{
    q_status_message(SM_ORDER, 3, 3, errormsg);
}
Esempio n. 13
0
/*
 * Setup CollectionLists. Build a context list on the fly from the config
 * variable and edit it. This won't include Incoming-Folders because that
 * is a pseudo collection, but that's ok since we can't do the operations
 * on it, anyway. Reset real config list at the end.
 */
void
context_config_screen(struct pine *ps, CONT_SCR_S *cs, int edit_exceptions)
{
    CONTEXT_S    *top, **clist, *cp;
    CONF_S	 *ctmpa, *first_line, *heading;
    OPT_SCREEN_S  screen;
    int           i, readonly_warning, some_defined, ret;
    int           reinit_contexts = 0, prime;
    char        **lval, **lval1, **lval2, ***alval;
    struct variable fake_fspec_var, fake_nspec_var;
    struct variable *fake_fspec, *fake_nspec;

    ew = edit_exceptions ? ps_global->ew_for_except_vars : Main;

    if(ps->restricted)
      readonly_warning = 1;
    else{
	PINERC_S *prc = NULL;

	switch(ew){
	  case Main:
	    prc = ps->prc;
	    break;
	  case Post:
	    prc = ps->post_prc;
	    break;
	  default:
	    break;
	}

	readonly_warning = prc ? prc->readonly : 1;
	if(prc && prc->quit_to_edit){
	    quit_to_edit_msg(prc);
	    return;
	}
    }

go_again:
    top = NULL; ctmpa = NULL; first_line = NULL;
    some_defined = 0, prime = 0;
    fake_fspec = &fake_fspec_var;
    fake_nspec = &fake_nspec_var;
    memset((void *)fake_fspec, 0, sizeof(*fake_fspec));
    memset((void *)fake_nspec, 0, sizeof(*fake_nspec));

    /* so fixed_var() will work right */
    fake_fspec->is_list = 1;
    fake_nspec->is_list = 1;
    if((ps->vars[V_FOLDER_SPEC]).is_fixed){
	fake_fspec->is_fixed = 1;
	if((ps->vars[V_FOLDER_SPEC]).fixed_val.l
	   && (ps->vars[V_FOLDER_SPEC]).fixed_val.l[0]){
	    fake_fspec->fixed_val.l = (char **) fs_get(2 * sizeof(char *));
	    fake_fspec->fixed_val.l[0]
			    = cpystr((ps->vars[V_FOLDER_SPEC]).fixed_val.l[0]);
	    fake_fspec->fixed_val.l[1] = NULL;
	}
    }

    if((ps->vars[V_NEWS_SPEC]).is_fixed){
	fake_nspec->is_fixed = 1;
	if((ps->vars[V_NEWS_SPEC]).fixed_val.l
	   && (ps->vars[V_NEWS_SPEC]).fixed_val.l[0]){
	    fake_nspec->fixed_val.l = (char **) fs_get(2 * sizeof(char *));
	    fake_nspec->fixed_val.l[0] = cpystr(INHERIT);
	    fake_nspec->fixed_val.l[0]
			    = cpystr((ps->vars[V_NEWS_SPEC]).fixed_val.l[0]);
	    fake_nspec->fixed_val.l[1] = NULL;
	}
    }

    clist = &top;
    lval1 = LVAL(&ps->vars[V_FOLDER_SPEC], ew);
    lval2 = LVAL(&ps->vars[V_NEWS_SPEC], ew);

    alval = ALVAL(fake_fspec, ew);
    if(lval1)
      *alval = copy_list_array(lval1);
    else if(!edit_exceptions && ps->VAR_FOLDER_SPEC && ps->VAR_FOLDER_SPEC[0] &&
	    ps->VAR_FOLDER_SPEC[0][0])
      *alval = copy_list_array(ps->VAR_FOLDER_SPEC);
    else
      fake_fspec = NULL;

    if(fake_fspec){
	lval = LVAL(fake_fspec, ew);
	for(i = 0; lval && lval[i]; i++){
	    cp = NULL;
	    if(i == 0 && !strcmp(lval[i], INHERIT)){
		cp = (CONTEXT_S *)fs_get(sizeof(*cp));
		memset((void *)cp, 0, sizeof(*cp));
		cp->use = CNTXT_INHERIT;
		cp->label = cpystr("Default collections are inherited");
	    }
	    else if((cp = new_context(lval[i], &prime)) != NULL){
		cp->var.v = fake_fspec;
		cp->var.i = i;
	    }
	    
	    if(cp){
		*clist    = cp;			/* add it to list   */
		clist     = &cp->next;		/* prepare for next */
	    }
	}

	set_current_val(fake_fspec, FALSE, FALSE);
    }

    alval = ALVAL(fake_nspec, ew);
    if(lval2)
      *alval = copy_list_array(lval2);
    else if(!edit_exceptions && ps->VAR_NEWS_SPEC && ps->VAR_NEWS_SPEC[0] &&
	    ps->VAR_NEWS_SPEC[0][0])
      *alval = copy_list_array(ps->VAR_NEWS_SPEC);
    else
      fake_nspec = NULL;

    if(fake_nspec){
	lval = LVAL(fake_nspec, ew);
	for(i = 0; lval && lval[i]; i++){
	    cp = NULL;
	    if(i == 0 && !strcmp(lval[i], INHERIT)){
		cp = (CONTEXT_S *)fs_get(sizeof(*cp));
		memset((void *)cp, 0, sizeof(*cp));
		cp->use = CNTXT_INHERIT;
		cp->label = cpystr("Default collections are inherited");
	    }
	    else if((cp = new_context(lval[i], &prime)) != NULL){
		cp->var.v = fake_nspec;
		cp->var.i = i;
	    }
	    
	    if(cp){
		*clist    = cp;			/* add it to list   */
		clist     = &cp->next;		/* prepare for next */
	    }
	}

	set_current_val(fake_nspec, FALSE, FALSE);
    }
    
    for(cp = top; cp; cp = cp->next)
      if(!(cp->use & CNTXT_INHERIT)){
	  some_defined++;
	  break;
      }

    if(edit_exceptions && !some_defined){
	q_status_message(SM_ORDER, 3, 7,
 _("No exceptions to edit. First collection exception must be set by editing file"));
	free_contexts(&top);
	if(reinit_contexts){
	    free_contexts(&ps_global->context_list);
	    init_folders(ps_global);
	}

	return;
    }


    /* fix up prev pointers */
    for(cp = top; cp; cp = cp->next)
      if(cp->next)
	cp->next->prev = cp;

    new_confline(&ctmpa);		/* blank line */
    ctmpa->keymenu    = cs->keymenu;
    ctmpa->help       = cs->help.text;
    ctmpa->help_title = cs->help.title;
    ctmpa->tool       = context_config_tool;
    ctmpa->flags     |= (CF_NOSELECT | CF_B_LINE);

    for(cp = top; cp; cp = cp->next){
	new_confline(&ctmpa);
	heading		  = ctmpa;
	if(!(cp->use & CNTXT_INHERIT))
	  ctmpa->value	  = cpystr(cp->nickname ? cp->nickname : cp->context);

	ctmpa->var	  = cp->var.v;
	ctmpa->keymenu    = cs->keymenu;
	ctmpa->help       = cs->help.text;
	ctmpa->help_title = cs->help.title;
	ctmpa->tool       = context_config_tool;
	ctmpa->flags	 |= CF_STARTITEM;
	ctmpa->valoffset  = 4;
	ctmpa->d.c.ct     = cp;
	ctmpa->d.c.cs	  = cs;
	if(cp->use & CNTXT_INHERIT)
	  ctmpa->flags |= CF_INHERIT | CF_NOSELECT;

	if((!first_line && !(cp->use & CNTXT_INHERIT)) ||
	   (!(cp->use & CNTXT_INHERIT) &&
	    cp->var.v &&
	    (cs->starting_var == cp->var.v) &&
	    (cs->starting_varmem == cp->var.i)))
	  first_line = ctmpa;

	/* Add explanatory text */
	new_confline(&ctmpa);
	ctmpa->value	  = cpystr(cp->label ? cp->label : "* * *");
	ctmpa->keymenu	  = cs->keymenu;
	ctmpa->help	  = cs->help.text;
	ctmpa->help_title = cs->help.title;
	ctmpa->tool	  = context_config_tool;
	ctmpa->flags	 |= CF_NOSELECT;
	ctmpa->valoffset  = 8;

	/* Always add blank line, make's shuffling a little easier */
	new_confline(&ctmpa);
	heading->headingp  = ctmpa;		/* use headingp to mark end */
	ctmpa->keymenu	   = cs->keymenu;
	ctmpa->help	   = cs->help.text;
	ctmpa->help_title  = cs->help.title;
	ctmpa->tool	   = context_config_tool;
	ctmpa->flags	  |= CF_NOSELECT | CF_B_LINE;
	ctmpa->valoffset   = 0;
    }

    cs->starting_var = NULL;


    memset(&screen, 0, sizeof(screen));
    screen.ro_warning = readonly_warning;
    ret = conf_scroll_screen(ps, &screen, first_line, cs->title,
			     cs->print_string, 0);

    free_contexts(&top);
    
    if(ret)
      reinit_contexts++;

    /*
     * 15 means the tool wants us to reset and go again. The config var
     * has been changed. The contexts will be built again from the
     * config variable and the real contexts will be rebuilt below.
     * This is easier and safer than having the tools rebuild the context
     * list and the display correct. It's difficult to do because of all
     * the inheriting and defaulting going on.
     */
    if(ret == 15){
	if(edit_exceptions && !LVAL(fake_fspec, ew) && !LVAL(fake_nspec, ew)){
	    if(want_to(_("Really delete last exceptional collection"),
		       'n', 'n', h_config_context_del_except,
		       WT_FLUSH_IN) != 'y'){
		free_variable_values(fake_fspec);
		free_variable_values(fake_nspec);
		goto go_again;
	    }
	}

	/* resolve variable changes */
	if((lval1 && !equal_list_arrays(lval1, LVAL(fake_fspec, ew))) ||
	   (fake_fspec && !equal_list_arrays(ps->VAR_FOLDER_SPEC,
					     LVAL(fake_fspec, ew)))){
	    i = set_variable_list(V_FOLDER_SPEC,
				  LVAL(fake_fspec, ew), TRUE, ew);
	    set_current_val(&ps->vars[V_FOLDER_SPEC], TRUE, FALSE);

	    if(i)
	      q_status_message(SM_ORDER, 3, 3,
			       _("Trouble saving change, cancelled"));
	    else if(!edit_exceptions && lval1 && !LVAL(fake_fspec, ew)){
		cs->starting_var = fake_fspec;
		cs->starting_varmem = 0;
		q_status_message(SM_ORDER, 3, 3,
		       _("Deleted last Folder-Collection, reverting to default"));
	    }
	    else if(!edit_exceptions && !lval1 && !LVAL(fake_fspec, ew)){
		cs->starting_var = fake_fspec;
		cs->starting_varmem = 0;
		q_status_message(SM_ORDER, 3, 3,
	       _("Deleted default Folder-Collection, reverting back to default"));
	    }
	}

	if((lval2 && !equal_list_arrays(lval2, LVAL(fake_nspec, ew))) ||
	   (fake_nspec && !equal_list_arrays(ps->VAR_NEWS_SPEC,
					     LVAL(fake_nspec, ew)))){
	    i = set_variable_list(V_NEWS_SPEC,
				  LVAL(fake_nspec, ew), TRUE, ew);
	    set_news_spec_current_val(TRUE, FALSE);

	    if(i)
	      q_status_message(SM_ORDER, 3, 3,
			       _("Trouble saving change, cancelled"));
	    else if(!edit_exceptions && lval2 && !LVAL(fake_nspec, ew) &&
		    ps->VAR_NEWS_SPEC && ps->VAR_NEWS_SPEC[0] &&
		    ps->VAR_NEWS_SPEC[0][0]){
		cs->starting_var = fake_nspec;
		cs->starting_varmem = 0;
		q_status_message(SM_ORDER, 3, 3,
		       _("Deleted last News-Collection, reverting to default"));
	    }
	    else if(!edit_exceptions && !lval2 && !LVAL(fake_nspec, ew) &&
		    ps->VAR_NEWS_SPEC && ps->VAR_NEWS_SPEC[0] &&
		    ps->VAR_NEWS_SPEC[0][0]){
		cs->starting_var = fake_nspec;
		cs->starting_varmem = 0;
	        q_status_message(SM_ORDER, 3, 3,
	         _("Deleted default News-Collection, reverting back to default"));
	    }
	}

	free_variable_values(fake_fspec);
	free_variable_values(fake_nspec);
	goto go_again;
    }

    ps->mangled_screen = 1;

    /* make the real context list match the changed config variables */
    if(reinit_contexts){
	free_contexts(&ps_global->context_list);
	init_folders(ps_global);
    }
}
Esempio n. 14
0
void
osx_launch_special_handling(MCAP_CMD_S *mc_cmd, char *image_file)
{
    CFStringRef str_ref = NULL;
    CFURLRef url_ref = NULL;
    LSLaunchFSRefSpec launch_spec;
    FSRef app_ref, file_ref;
    static EXEC_EVENT_DATA_S event_data;

    install_app_launch_cb((void *)&event_data);
    if((str_ref = CFStringCreateWithCString(NULL, mc_cmd->command,
					kCFStringEncodingASCII)) == NULL)
      return;
    if((url_ref = CFURLCreateWithString(NULL, str_ref, NULL)) == NULL)
      return;
    if(CFURLGetFSRef(url_ref, &app_ref) == false)
      return;
    if(FSPathMakeRef((unsigned char *)image_file,
		     &file_ref, NULL) != noErr)
      return;
    launch_spec.appRef = &app_ref;
    launch_spec.numDocs = 1;
    launch_spec.itemRefs = &file_ref;
    launch_spec.passThruParams = NULL;
    launch_spec.launchFlags = kLSLaunchDontAddToRecents | kLSLaunchNoParams
      | kLSLaunchAsync | kLSLaunchNewInstance;
    /* would want to use this if we ever did true event handling */
    launch_spec.asyncRefCon = 0;

    if(LSOpenFromRefSpec( &launch_spec, NULL) == noErr){
	/*
	 * Here's the strategy:  we want to be able to just launch
	 * the app and then just delete the temp file, but that
	 * doesn't work because the called app needs the temp file
	 * at least until it's finished loading.  Being that there's
	 * no way to tell when the app has finished loading, we wait
	 * until the program has exited, which is the safest thing to
	 * do and is what we do for windows.  Since we haven't totally
	 * embraced event handling at this point, we must do the waiting
	 * synchronously.  We allow for a keystroke to stop waiting, and
	 * just delete the temp file.
	 *   Ideally, we would launch the app, and keep running, checking
	 * the events until the process terminates, and then delete the
	 * temp file.  In this method, we would delete the temp file
	 * at close time if the app was still running.
	 */
	int ch;
	OSStatus rne_rv;
	EventTargetRef target;
	EventRef out_event;
	EventTypeSpec event_types[2] = {
	    {kEventClassApplication, kEventAppTerminated},
	    {kEventClassApplication, kEventAppLaunchNotification}};

	q_status_message(SM_ORDER, 0, 4,
	  "Waiting for program to finish, or press a key to stop waiting...");
	flush_status_messages(1);
	target = GetEventDispatcherTarget();
	event_data.done = 0;
	event_data.set_pid = 0;
	while(!event_data.done){
	    if((rne_rv = ReceiveNextEvent(2, event_types, 1,
					  true, &out_event)) == noErr){
		SendEventToEventTarget(out_event, target);
		ReleaseEvent(out_event);
	    }
	    else if(rne_rv == eventLoopTimedOutErr){
		ch = read_char(1);
		if(ch)
		  event_data.done = 1;
	    }
	    else if(rne_rv == eventLoopQuitErr)
	      event_data.done = 1;
	}
	our_unlink(image_file);
    }
    q_status_message(SM_ORDER, 0, 4, "VIEWER command completed");
}
Esempio n. 15
0
int
context_config_shuffle(struct pine *ps, CONF_S **cl)
{
    char      prompt[256];
    int	      n = 0, cmd, i1, i2, count = 0, insert_num, starting_varmem;
    int       news_problem = 0, deefault = 0;
    ESCKEY_S  ekey[3];
    CONTEXT_S *cur_ctxt, *other_ctxt;
    char     *tmp, **lval, **lval1, **lval2;
    struct variable *cur_var, *other_var;

    if(!((*cl)->d.c.ct && (*cl)->var))
      return(0);

    /* enable UP? */
    if((*cl)->d.c.ct->prev && !((*cl)->d.c.ct->prev->use & CNTXT_INHERIT)){
	/*
	 * Don't allow shuffling news collection up to become
	 * the primary collection. That would happen if prev is primary
	 * and this one is news.
	 */
	if((*cl)->d.c.ct->prev->use & CNTXT_SAVEDFLT &&
	   (*cl)->d.c.ct->use & CNTXT_NEWS)
	  news_problem++;
	else{
	    ekey[n].ch      = 'u';
	    ekey[n].rval    = 'u';
	    ekey[n].name    = "U";
	    ekey[n++].label = N_("Up");
	    deefault        = 'u';
	}
    }

    /* enable DOWN? */
    if((*cl)->d.c.ct->next && !((*cl)->d.c.ct->next->use & CNTXT_INHERIT)){
	/*
	 * Don't allow shuffling down past news collection if this
	 * is primary collection.
	 */
	if((*cl)->d.c.ct->use & CNTXT_SAVEDFLT &&
	   (*cl)->d.c.ct->next->use & CNTXT_NEWS)
	  news_problem++;
	else{
	    ekey[n].ch      = 'd';
	    ekey[n].rval    = 'd';
	    ekey[n].name    = "D";
	    ekey[n++].label = N_("Down");
	    if(!deefault)
	      deefault = 'd';
	}
    }

    if(n){
	ekey[n].ch = -1;
	snprintf(prompt, sizeof(prompt), _("Shuffle selected context %s%s%s? "),
		(ekey[0].ch == 'u') ?  _("UP") : "",
		(n > 1) ? " or " : "",
		(ekey[0].ch == 'd' || n > 1) ? _("DOWN") : "");
	prompt[sizeof(prompt)-1] = '\0';

	cmd = radio_buttons(prompt, -FOOTER_ROWS(ps), ekey,
			    deefault, 'x', NO_HELP, RB_NORM);
	switch(cmd){
	  case 'x':
	  default:
	    cmd_cancelled("Shuffle");
	    return(0);
	  
	  case 'u':
	  case 'd':
	    break;
	}

	/*
	 * This is complicated by the fact that there are two
	 * vars involved, the folder-collections and the news-collections.
	 * We may have to shuffle across collections.
	 */
	cur_ctxt = (*cl)->d.c.ct;
	if(cmd == 'd')
	  other_ctxt = (*cl)->d.c.ct->next;
	else if(cmd == 'u')
	  other_ctxt = (*cl)->d.c.ct->prev;
	
	cur_var = cur_ctxt->var.v;
	other_var = other_ctxt->var.v;

	/* swap elements of config var */
	if(cur_var == other_var){
	    i1 = cur_ctxt->var.i;
	    i2 = other_ctxt->var.i;
	    lval = LVAL(cur_var, ew);
	    if(lval){
		tmp = lval[i1];
		lval[i1] = lval[i2];
		lval[i2] = tmp;
	    }

	    starting_varmem = i2;
	}
	else{
	    /* swap into the other_var */
	    i1 = cur_ctxt->var.i;
	    i2 = other_ctxt->var.i;
	    lval1 = LVAL(cur_var, ew);
	    lval2 = LVAL(other_var, ew);
	    /* count */
	    for(count = 0; lval2 && lval2[count]; count++)
	      ;
	    if(cmd == 'd')
	      insert_num = count ? 1 : 0;
	    else{
		insert_num = count ? count - 1 : count;
	    }

	    starting_varmem = insert_num;
	    if(ccs_var_insert(ps,lval1[i1],other_var,lval2,insert_num)){
		if(!ccs_var_delete(ps, cur_ctxt)){
		    q_status_message(SM_ORDER|SM_DING, 3, 3,
				     _("Error deleting shuffled context"));
		    return(0);
		}
	    }
	    else{
		q_status_message(SM_ORDER, 3, 3,
				 _("Trouble shuffling, cancelled"));
		return(0);
	    }
	}

	(*cl)->d.c.cs->starting_var = other_var;
	(*cl)->d.c.cs->starting_varmem = starting_varmem;

	q_status_message(SM_ORDER, 0, 3, _("Collections shuffled"));
	return(15);
    }

    if(news_problem)
      /* TRANSLATORS: Sorry, can't move news group collections above email collections */
      q_status_message(SM_ORDER, 0, 3, _("Sorry, cannot Shuffle news to top"));
    else
      q_status_message(SM_ORDER, 0, 3, _("Sorry, nothing to Shuffle"));

    return(0);
}
Esempio n. 16
0
/*----------------------------------------------------------------------
    Present pinerc data for manipulation

    Args: None

  Result: help edit certain pinerc fields.
  ---*/
void
option_screen(struct pine *ps, int edit_exceptions)
{
    char	    tmp[MAXPATH+1], *pval, **lval;
    int		    i, j, ln = 0, readonly_warning = 0;
    struct	    variable  *vtmp;
    CONF_S	   *ctmpa = NULL, *ctmpb, *first_line = NULL;
    FEATURE_S	   *feature;
    PINERC_S       *prc = NULL;
    SAVED_CONFIG_S *vsave;
    OPT_SCREEN_S    screen;
    int             expose_hidden_config, add_hidden_vars_title = 0;

    dprint((3, "-- option_screen --\n"));

    expose_hidden_config = F_ON(F_EXPOSE_HIDDEN_CONFIG, ps_global);
    treat_color_vars_as_text = expose_hidden_config;

    ew = edit_exceptions ? ps_global->ew_for_except_vars : Main;

    if(ps->restricted)
      readonly_warning = 1;
    else{
	switch(ew){
	  case Main:
	    prc = ps->prc;
	    break;
	  case Post:
	    prc = ps->post_prc;
	    break;
	  default:
	    break;
	}

	readonly_warning = prc ? prc->readonly : 1;
	if(prc && prc->quit_to_edit){
	    quit_to_edit_msg(prc);
	    treat_color_vars_as_text = 0;
	    return;
	}
    }

    ps->next_screen = SCREEN_FUN_NULL;

    mailcap_free(); /* free resources we won't be using for a while */

    if(ps->fix_fixed_warning)
      offer_to_fix_pinerc(ps);

    /*
     * First, find longest variable name
     */
    for(vtmp = ps->vars; vtmp->name; vtmp++){
	if(exclude_config_var(ps, vtmp, expose_hidden_config))
	  continue;

	if((i = utf8_width(pretty_var_name(vtmp->name))) > ln)
	  ln = i;
    }

    dprint((9, "initialize config list\n"));

    /*
     * Next, allocate and initialize config line list...
     */
    for(vtmp = ps->vars; vtmp->name; vtmp++){
	/*
	 * INCOMING_FOLDERS is currently the first of the normally
	 * hidden variables. Should probably invent a more robust way
	 * to keep this up to date.
	 */
	if(expose_hidden_config && vtmp == &ps->vars[V_INCOMING_FOLDERS])
	  add_hidden_vars_title = 1;

	if(exclude_config_var(ps, vtmp, expose_hidden_config))
	  continue;

	if(add_hidden_vars_title){

	    add_hidden_vars_title = 0;

	    new_confline(&ctmpa);		/* Blank line */
	    ctmpa->flags	       |= CF_NOSELECT | CF_B_LINE;

	    new_confline(&ctmpa)->var	= NULL;
	    ctmpa->help			= NO_HELP;
	    ctmpa->valoffset		= 2;
	    ctmpa->flags	       |= CF_NOSELECT;
	    ctmpa->value = cpystr("--- [ Normally hidden configuration options ] ---");

	    new_confline(&ctmpa);		/* Blank line */
	    ctmpa->flags	       |= CF_NOSELECT | CF_B_LINE;
	}

	if(vtmp->is_list)
	  lval  = LVAL(vtmp, ew);
	else
	  pval  = PVAL(vtmp, ew);

	new_confline(&ctmpa)->var = vtmp;
	if(!first_line)
	  first_line = ctmpa;

	ctmpa->valoffset = ln + 3;
	if(vtmp->is_list)
	  ctmpa->keymenu	 = &config_text_wshuf_keymenu;
	else
	  ctmpa->keymenu	 = &config_text_keymenu;
	  
	ctmpa->help	 = config_help(vtmp - ps->vars, 0);
	ctmpa->tool	 = text_tool;

	utf8_snprintf(tmp, sizeof(tmp), "%-*.100w =", ln, pretty_var_name(vtmp->name));
	tmp[sizeof(tmp)-1] = '\0';
	ctmpa->varname  = cpystr(tmp);
	ctmpa->varnamep = ctmpb = ctmpa;
	ctmpa->flags   |= CF_STARTITEM;
	if(vtmp == &ps->vars[V_FEATURE_LIST]){	/* special checkbox case */
	    char *this_sect, *new_sect;

	    ctmpa->flags		 |= CF_NOSELECT;
	    ctmpa->keymenu		  = &config_checkbox_keymenu;
	    ctmpa->tool			  = NULL;

	    /* put a nice delimiter before list */
	    new_confline(&ctmpa)->var = NULL;
	    ctmpa->varnamep		  = ctmpb;
	    ctmpa->keymenu		  = &config_checkbox_keymenu;
	    ctmpa->help			  = NO_HELP;
	    ctmpa->tool			  = checkbox_tool;
	    ctmpa->valoffset		  = feature_indent();
	    ctmpa->flags		 |= CF_NOSELECT;
	    ctmpa->value = cpystr("Set    Feature Name");

	    new_confline(&ctmpa)->var = NULL;
	    ctmpa->varnamep		  = ctmpb;
	    ctmpa->keymenu		  = &config_checkbox_keymenu;
	    ctmpa->help			  = NO_HELP;
	    ctmpa->tool			  = checkbox_tool;
	    ctmpa->valoffset		  = feature_indent();
	    ctmpa->flags		 |= CF_NOSELECT;
	    ctmpa->value = cpystr("---  ----------------------");

	    for(i = 0, this_sect = NULL; (feature = feature_list(i)); i++)
	      if((new_sect = feature_list_section(feature)) &&
		 (strcmp(new_sect, HIDDEN_PREF) != 0)){
		  if(this_sect != new_sect){
		      new_confline(&ctmpa)->var = NULL;
		      ctmpa->varnamep		= ctmpb;
		      ctmpa->keymenu		= &config_checkbox_keymenu;
		      ctmpa->help		= NO_HELP;
		      ctmpa->tool		= checkbox_tool;
		      ctmpa->valoffset		= 2;
		      ctmpa->flags	       |= (CF_NOSELECT | CF_STARTITEM);
		      snprintf(tmp, sizeof(tmp), "[ %s ]", this_sect = new_sect);
		      tmp[sizeof(tmp)-1] = '\0';
		      ctmpa->value = cpystr(tmp);
		  }

		  new_confline(&ctmpa)->var = vtmp;
		  ctmpa->varnamep	    = ctmpb;
		  ctmpa->keymenu	    = &config_checkbox_keymenu;
		  ctmpa->help		    = config_help(vtmp-ps->vars,
							  feature->id);
		  ctmpa->tool		    = checkbox_tool;
		  ctmpa->valoffset	    = feature_indent();
		  ctmpa->varmem		    = i;
		  ctmpa->value		    = pretty_value(ps, ctmpa);
	      }
	}
	else if(standard_radio_var(ps, vtmp)){
	    standard_radio_setup(ps, &ctmpa, vtmp, NULL);
	}
	else if(vtmp == &ps->vars[V_SORT_KEY]){ /* radio case */
	    SortOrder def_sort;
	    int       def_sort_rev;

	    ctmpa->flags       |= CF_NOSELECT;
	    ctmpa->keymenu      = &config_radiobutton_keymenu;
	    ctmpa->tool		= NULL;

	    /* put a nice delimiter before list */
	    new_confline(&ctmpa)->var = NULL;
	    ctmpa->varnamep		  = ctmpb;
	    ctmpa->keymenu		  = &config_radiobutton_keymenu;
	    ctmpa->help			  = NO_HELP;
	    ctmpa->tool			  = radiobutton_tool;
	    ctmpa->valoffset		  = 12;
	    ctmpa->flags		 |= CF_NOSELECT;
	    ctmpa->value = cpystr("Set    Sort Options");

	    new_confline(&ctmpa)->var = NULL;
	    ctmpa->varnamep	      = ctmpb;
	    ctmpa->keymenu	      = &config_radiobutton_keymenu;
	    ctmpa->help		      = NO_HELP;
	    ctmpa->tool		      = radiobutton_tool;
	    ctmpa->valoffset	      = 12;
	    ctmpa->flags             |= CF_NOSELECT;
	    ctmpa->value = cpystr("---  ----------------------");

	    decode_sort(pval, &def_sort, &def_sort_rev);

	    for(j = 0; j < 2; j++){
		for(i = 0; ps->sort_types[i] != EndofList; i++){
		    new_confline(&ctmpa)->var = vtmp;
		    ctmpa->varnamep	      = ctmpb;
		    ctmpa->keymenu	      = &config_radiobutton_keymenu;
		    ctmpa->help		      = config_help(vtmp - ps->vars, 0);
		    ctmpa->tool		      = radiobutton_tool;
		    ctmpa->valoffset	      = 12;
		    ctmpa->varmem	      = i + (j * EndofList);
		    ctmpa->value	      = pretty_value(ps, ctmpa);
		}
	    }
	}
	else if(vtmp == &ps->vars[V_USE_ONLY_DOMAIN_NAME]){ /* yesno case */
	    ctmpa->keymenu = &config_yesno_keymenu;
	    ctmpa->tool	   = yesno_tool;
	    ctmpa->value   = pretty_value(ps, ctmpa);
	}
	else if(vtmp == &ps->vars[V_LITERAL_SIG]){
	    ctmpa->tool    = litsig_text_tool;
	    ctmpa->value   = pretty_value(ps, ctmpa);
	}
	else if(vtmp == &ps->vars[V_INBOX_PATH]){
	    ctmpa->tool    = inbox_path_text_tool;
	    ctmpa->value   = pretty_value(ps, ctmpa);
	}
	else if(vtmp == &ps->vars[V_POST_CHAR_SET]
#ifndef _WINDOWS
		|| vtmp == &ps->vars[V_CHAR_SET]
	        || vtmp == &ps->vars[V_KEY_CHAR_SET]
#endif /* !_WINDOWS */
		|| vtmp == &ps->vars[V_UNK_CHAR_SET]){
	    ctmpa->keymenu = &config_text_to_charsets_keymenu;
	    ctmpa->tool    = to_charsets_text_tool;
	    ctmpa->value   = pretty_value(ps, ctmpa);
	}
	else if(vtmp->is_list){
	    int (*t_tool)(struct pine *, int, CONF_S **, unsigned);
	    struct key_menu *km;

	    t_tool = NULL;
	    km = NULL;
	    if(vtmp == &ps->vars[V_INCCHECKLIST]){
		t_tool = incoming_monitoring_list_tool;
		km     = &config_text_keymenu;
	    }
	    else if(vtmp == &ps->vars[V_PERMLOCKED]){
		t_tool = stayopen_list_tool;
		km     = &config_text_wshufandfldr_keymenu;
	    }

	    if(lval){
		for(i = 0; lval[i]; i++){
		    if(i)
		      (void)new_confline(&ctmpa);

		    ctmpa->var       = vtmp;
		    ctmpa->varmem    = i;
		    ctmpa->valoffset = ln + 3;
		    ctmpa->value     = pretty_value(ps, ctmpa);
		    ctmpa->keymenu   = km ? km : &config_text_wshuf_keymenu;
		    ctmpa->help      = config_help(vtmp - ps->vars, 0);
		    ctmpa->tool      = t_tool ? t_tool : text_tool;
		    ctmpa->varnamep  = ctmpb;
		}
	    }
	    else{
		ctmpa->varmem = 0;
		ctmpa->value  = pretty_value(ps, ctmpa);
		ctmpa->tool   = t_tool ? t_tool : text_tool;
		ctmpa->keymenu = km ? km : &config_text_wshuf_keymenu;
	    }
	}
	else{
	    if(vtmp == &ps->vars[V_FILLCOL]
	       || vtmp == &ps->vars[V_SLEEP]
	       || vtmp == &ps->vars[V_QUOTE_SUPPRESSION]
	       || vtmp == &ps->vars[V_OVERLAP]
	       || vtmp == &ps->vars[V_MAXREMSTREAM]
	       || vtmp == &ps->vars[V_MARGIN]
	       || vtmp == &ps->vars[V_DEADLETS]
	       || vtmp == &ps->vars[V_NMW_WIDTH]
	       || vtmp == &ps->vars[V_STATUS_MSG_DELAY]
	       || vtmp == &ps->vars[V_ACTIVE_MSG_INTERVAL]
	       || vtmp == &ps->vars[V_MAILCHECK]
	       || vtmp == &ps->vars[V_MAILCHECKNONCURR]
	       || vtmp == &ps->vars[V_MAILDROPCHECK]
	       || vtmp == &ps->vars[V_NNTPRANGE]
	       || vtmp == &ps->vars[V_TCPOPENTIMEO]
	       || vtmp == &ps->vars[V_TCPREADWARNTIMEO]
	       || vtmp == &ps->vars[V_TCPWRITEWARNTIMEO]
	       || vtmp == &ps->vars[V_TCPQUERYTIMEO]
	       || vtmp == &ps->vars[V_RSHOPENTIMEO]
	       || vtmp == &ps->vars[V_SSHOPENTIMEO]
	       || vtmp == &ps->vars[V_INCCHECKTIMEO]
	       || vtmp == &ps->vars[V_INCCHECKINTERVAL]
	       || vtmp == &ps->vars[V_INC2NDCHECKINTERVAL]
	       || vtmp == &ps->vars[V_USERINPUTTIMEO]
	       || vtmp == &ps->vars[V_REMOTE_ABOOK_VALIDITY]
	       || vtmp == &ps->vars[V_REMOTE_ABOOK_HISTORY])
	      ctmpa->flags |= CF_NUMBER;

	    ctmpa->value = pretty_value(ps, ctmpa);
	}
    }

    dprint((9, "add hidden features\n"));

    /* add the hidden features */
    if(expose_hidden_config){
	char *new_sect;

	new_confline(&ctmpa);		/* Blank line */
	ctmpa->flags	       |= CF_NOSELECT | CF_B_LINE;

	new_confline(&ctmpa)->var	= NULL;
	ctmpa->help			= NO_HELP;
	ctmpa->valoffset		= 2;
	ctmpa->flags	       |= CF_NOSELECT;
	ctmpa->value = cpystr("--- [ Normally hidden configuration features ] ---");

	new_confline(&ctmpa);		/* Blank line */
	ctmpa->flags	       |= CF_NOSELECT | CF_B_LINE;

	vtmp = &ps->vars[V_FEATURE_LIST];

	ctmpa->flags		 |= CF_NOSELECT;
	ctmpa->keymenu		  = &config_checkbox_keymenu;
	ctmpa->tool			  = NULL;

	/* put a nice delimiter before list */
	new_confline(&ctmpa)->var = NULL;
	ctmpa->varnamep		  = ctmpb;
	ctmpa->keymenu		  = &config_checkbox_keymenu;
	ctmpa->help			  = NO_HELP;
	ctmpa->tool			  = checkbox_tool;
	ctmpa->valoffset		  = feature_indent();
	ctmpa->flags		 |= CF_NOSELECT;
	ctmpa->value = cpystr("Set    Feature Name");

	new_confline(&ctmpa)->var = NULL;
	ctmpa->varnamep		  = ctmpb;
	ctmpa->keymenu		  = &config_checkbox_keymenu;
	ctmpa->help			  = NO_HELP;
	ctmpa->tool			  = checkbox_tool;
	ctmpa->valoffset		  = feature_indent();
	ctmpa->flags		 |= CF_NOSELECT;
	ctmpa->value = cpystr("---  ----------------------");

	for(i = 0; (feature = feature_list(i)); i++)
	  if((new_sect = feature_list_section(feature)) &&
	     (strcmp(new_sect, HIDDEN_PREF) == 0)){

	      new_confline(&ctmpa)->var	= vtmp;
	      ctmpa->varnamep		= ctmpb;
	      ctmpa->keymenu		= &config_checkbox_keymenu;
	      ctmpa->help		= config_help(vtmp-ps->vars,
						      feature->id);
	      ctmpa->tool		= checkbox_tool;
	      ctmpa->valoffset		= feature_indent();
	      ctmpa->varmem		= i;
	      ctmpa->value		= pretty_value(ps, ctmpa);
	  }
    }

    vsave = save_config_vars(ps, expose_hidden_config);
    first_line = first_sel_confline(first_line);

    memset(&screen, 0, sizeof(screen));
    screen.ro_warning = readonly_warning;
    /* TRANSLATORS: Print something1 using something2.
       "configuration" is something1 */
    switch(conf_scroll_screen(ps, &screen, first_line,
			      edit_exceptions ? CONFIG_SCREEN_TITLE_EXC
					      : CONFIG_SCREEN_TITLE,
			      _("configuration"), 0)){
      case 0:
	break;

      case 1:
	write_pinerc(ps, ew, WRP_NONE);
	break;
    
      case 10:
	revert_to_saved_config(ps, vsave, expose_hidden_config);
	if(prc)
	  prc->outstanding_pinerc_changes = 0;

	break;
      
      default:
	q_status_message(SM_ORDER,7,10,
	    "conf_scroll_screen bad ret, not supposed to happen");
	break;
    }

    pval = PVAL(&ps->vars[V_SORT_KEY], ew);
    if(vsave[V_SORT_KEY].saved_user_val.p && pval
       && strcmp(vsave[V_SORT_KEY].saved_user_val.p, pval)){
	if(!mn_get_mansort(ps_global->msgmap)){
	    clear_index_cache(ps_global->mail_stream, 0);
	    reset_sort_order(SRT_VRB);
	}
    }

    treat_color_vars_as_text = 0;
    free_saved_config(ps, &vsave, expose_hidden_config);
#ifdef _WINDOWS
    mswin_set_quit_confirm (F_OFF(F_QUIT_WO_CONFIRM, ps_global));
#endif
}
Esempio n. 17
0
/*
 * Turn on a busy cue.
 *
 *    msg   -- the busy message to print in status line
 *    pc_f  -- if non-null, call this function to get the percent done,
 *	       (an integer between 0 and 100).  If null, append dots.
 *   delay  -- seconds to delay output of delay notification
 *
 *   Returns:  0 If busy cue was already set up before we got here
 *             1 If busy cue was not already set up.
 *
 *   NOTE: busy_cue and cancel_busy_cue MUST be called symetrically in the
 *         same lexical scope.
 */
int
busy_cue(char *msg, percent_done_t pc_f, int delay)
{
    AFTER_S *a = NULL, **ap;

    dprint((9, "busy_cue(%s, %p, %d)\n", msg ? msg : "Busy", pc_f, delay));

    if(!(ps_global && ps_global->ttyo)){
	dprint((9, "busy_cue returns No (ttyo)"));
	return(0);
    }

    /*
     * If we're already busy'ing, but a cue is invoked that
     * supplies more useful info, use it...
     */
    if(after_active){
	if(msg || pc_f)
	  stop_after(1);	/* uninstall old handler */
	else
	  return(0);		/* nothing to add, return */
    }

    /* get ready to set up list of AFTER_S's */
    ap = &a;

    dotcount = 0;
    percent_done_ptr = pc_f;

    if(msg){
	strncpy(busy_message, msg, sizeof(busy_message));
	final_message = 1;
    }
    else{
	strncpy(busy_message, "Busy", sizeof(busy_message));
	final_message = 0;
    }

    busy_message[sizeof(busy_message)-1] = '\0';
    busy_width = utf8_width(busy_message);

    if(!delay){
	char progress[MAX_SCREEN_COLS+1];
	int space_left, slots_used;

	final_message = 1;
	space_left = (ps_global->ttyo ? ps_global->ttyo->screen_cols
		      : 80) - busy_width - 2;  /* 2 is for [] */
	slots_used = MAX(0, MIN(space_left-3, 10));

	if(percent_done_ptr && slots_used >= 4){
	    snprintf(progress, sizeof(progress), "%s |%*s|", busy_message, slots_used, "");
	    progress[sizeof(progress)-1] = '\0';
	}
	else{
	    dotcount++;
	    snprintf(progress, sizeof(progress), "%s%*s", busy_message,
		     spinners[spinner].width + 1, "");
	    progress[sizeof(progress)-1] = '\0';
	}


	if(status_message_remaining()){
	    char buf[sizeof(progress) + 30];
	    char  *append = " [not actually shown]";

	    strncpy(buf, progress, sizeof(buf)-1);
	    buf[sizeof(buf)-1] = '\0';

	    strncat(buf, append, sizeof(buf) - strlen(buf) - 1);
	    buf[sizeof(buf)-1] = '\0';

	    add_review_message(buf, -1);
	}
	else{
	    q_status_message(SM_ORDER, 0, 1, progress);

	    /*
	     * We use display_message so that the initial message will
	     * be forced out only if there is not a previous message
	     * currently being displayed that hasn't been displayed for
	     * its min display time yet.  In that case, we don't want
	     * to force out the initial message.
	     */
	    display_message('x');
	}
	
	fflush(stdout);
    }

    /*
     * Randomly select one of the animations, even taking care
     * to run through all of them before starting over!
     * The user won't actually see them all because most of them
     * will never show up before they are canceled, but it
     * should still help.
     */
    spinner = -1;
    if(F_OFF(F_USE_BORING_SPINNER,ps_global) && ps_global->active_status_interval > 0){
	int arrsize, eligible, pick_this_one, i, j;

	arrsize = sizeof(spinners)/sizeof(struct _spinner);

	/* how many of them are eligible to be used this round? */
	for(eligible = i = 0; i < arrsize; i++)
	  if(!spinners[i].used_this_round)
	    eligible++;

	if(eligible == 0)				/* reset */
	  for(eligible = i = 0; i < arrsize; i++){
	      spinners[i].used_this_round = 0;
	      eligible++;
	  }

	if(eligible > 0){	/* it will be */
	    pick_this_one = random() % eligible;
	    for(j = i = 0; i < arrsize && spinner < 0; i++)
	      if(!spinners[i].used_this_round){
		  if(j == pick_this_one)
		    spinner = i;
		  else
		    j++;
	      }
	}
    }

    if(spinner < 0 || spinner > sizeof(spinners)/sizeof(struct _spinner) -1)
      spinner = 0;

    *ap		 = new_afterstruct();
    (*ap)->delay = (pc_f) ? BUSY_DELAY_PERCENT : BUSY_DELAY_SPINNER;
    (*ap)->f	 = do_busy_cue;
    (*ap)->cf	 = done_busy_cue;
    ap		 = &(*ap)->next;

    start_after(a);		/* launch cue handler */

#ifdef _WINDOWS
    mswin_setcursor(MSWIN_CURSOR_BUSY);
#endif

    return(1);
}
Esempio n. 18
0
/*----------------------------------------------------------------------
    The printer selection screen

   Draws the screen and prompts for the printer number and the custom
   command if so selected.

 ----*/
void
select_printer(struct pine *ps, int edit_exceptions)
{
    struct        variable  *vtmp;
    CONF_S       *ctmpa = NULL, *ctmpb = NULL, *heading = NULL,
		 *start_line = NULL;
    PINERC_S     *prc = NULL;
    int i, saved_printer_cat, readonly_warning = 0, no_ex;
    SAVED_CONFIG_S *vsave;
    char *saved_printer, **lval;
    OPT_SCREEN_S screen;
    size_t l;

    if(edit_exceptions){
	q_status_message(SM_ORDER, 3, 7,
			 _("Exception Setup not implemented for printer"));
	return;
    }

    if(fixed_var(&ps_global->vars[V_PRINTER], "change", "printer"))
      return;

    ew = edit_exceptions ? ps_global->ew_for_except_vars : Main;
    
    no_ex = (ps_global->ew_for_except_vars == Main);

    if(ps->restricted)
      readonly_warning = 1;
    else{
	switch(ew){
	  case Main:
	    prc = ps->prc;
	    break;
	  case Post:
	    prc = ps->post_prc;
	    break;
	  default:
	    break;
	}

	readonly_warning = prc ? prc->readonly : 1;
	if(prc && prc->quit_to_edit){
	    quit_to_edit_msg(prc);
	    return;
	}
    }

    saved_printer = cpystr(ps->VAR_PRINTER);
    saved_printer_cat = ps->printer_category;

    new_confline(&ctmpa);
    ctmpa->valoffset = 2;
    ctmpa->keymenu   = &printer_select_keymenu;
    ctmpa->help      = NO_HELP;
    ctmpa->tool      = print_select_tool;
    ctmpa->flags    |= CF_NOSELECT;
    ctmpa->value
#ifdef OS2
      = cpystr("\"Select\" a port or |pipe-command as your default printer.");
#else
      = cpystr(_("You may \"Select\" a print command as your default printer."));
Esempio n. 19
0
int
context_config_delete(struct pine *ps, CONF_S **cl)
{
    char       tmp[MAILTMPLEN];

    if(!(*cl)->var){
	q_status_message(SM_ORDER|SM_DING, 3, 3,
			 "Programmer botch in context_config_delete");
	return(0);
    }

    if((*cl)->d.c.ct->use & CNTXT_SAVEDFLT &&
       (*cl)->d.c.ct->next &&
       (*cl)->d.c.ct->next->use & CNTXT_NEWS &&
       (*cl)->d.c.ct->var.v == (*cl)->d.c.ct->next->var.v){
	q_status_message(SM_ORDER|SM_DING, 3, 3,
			 _("Sorry, cannot Delete causing news to move to top"));
	return(0);
    }

    snprintf(tmp, sizeof(tmp), _("Delete the collection definition for \"%s\""),
	    (*cl)->value);
    tmp[sizeof(tmp)-1] = '\0';
    if(want_to(tmp, 'n', 'n', NO_HELP, WT_FLUSH_IN) == 'y'){

	(*cl)->d.c.cs->starting_var = (*cl)->var;
	(*cl)->d.c.cs->starting_varmem = (*cl)->d.c.ct->var.i;
	if((*cl)->d.c.ct->next){
	    if((*cl)->d.c.ct->next->var.v != (*cl)->var){
		(*cl)->d.c.cs->starting_var = (*cl)->d.c.ct->next->var.v;
		(*cl)->d.c.cs->starting_varmem = 0;
	    }
	    else{
		(*cl)->d.c.cs->starting_var = (*cl)->var;
		(*cl)->d.c.cs->starting_varmem = (*cl)->d.c.ct->var.i;
	    }
	}
	else{
	    if((*cl)->d.c.ct->var.i > 0){
		(*cl)->d.c.cs->starting_var = (*cl)->var;
		(*cl)->d.c.cs->starting_varmem = (*cl)->d.c.ct->var.i - 1;
	    }
	    else{
		if((*cl)->d.c.ct->prev){
		    (*cl)->d.c.cs->starting_var = (*cl)->d.c.ct->prev->var.v;
		    (*cl)->d.c.cs->starting_varmem = (*cl)->d.c.ct->prev->var.i;
		}
	    }
	}
	  
	/* Remove from var list */
	if(!ccs_var_delete(ps, (*cl)->d.c.ct)){
	    q_status_message(SM_ORDER|SM_DING, 3, 3,
			     _("Error deleting renamed context"));
	    return(0);
	}

	q_status_message(SM_ORDER, 0, 3, _("Collection deleted"));

	return(15);
    }

    q_status_message(SM_ORDER, 0, 3, _("No collections deleted"));
    return(0);
}
Esempio n. 20
0
int
context_config_edit(struct pine *ps, CONF_S **cl)
{
    char            *raw_ctxt, tpath[MAILTMPLEN], *p, **lval;
    struct variable *var;
    int              i;

    if(!(*cl)->d.c.ct)
      return(0);

    /* Undigest the context */
    strncpy(tpath, ((*cl)->d.c.ct->context[0] == '{'
		    && (p = strchr((*cl)->d.c.ct->context, '}')))
		      ? ++p
		      : (*cl)->d.c.ct->context, sizeof(tpath)-1);
    tpath[sizeof(tpath)-1] = '\0';

    if((p = strstr(tpath, "%s")) != NULL)
      *p = '\0';

    if((raw_ctxt = context_edit_screen(ps, "EDIT", (*cl)->d.c.ct->nickname,
				      (*cl)->d.c.ct->server, tpath,
				      (*cl)->d.c.ct->dir ?
				             (*cl)->d.c.ct->dir->view.user
					     : NULL)) != NULL){

	if((*cl)->var){
	    var = (*cl)->var;
	    lval = LVAL(var, ew);
	    i = (*cl)->d.c.ct->var.i;

	    if(lval && lval[i] && !strcmp(lval[i], raw_ctxt))
	      q_status_message(SM_ORDER, 0, 3, _("No change"));
	    else if(lval){
		if(lval[i])
		  fs_give((void **) &lval[i]);

		lval[i] = raw_ctxt;
		raw_ctxt = NULL;

		q_status_message(SM_ORDER, 0, 3, _("Collection list entry updated"));
	    }

	    (*cl)->d.c.cs->starting_var = var;
	    (*cl)->d.c.cs->starting_varmem = i;

	    if(raw_ctxt)
	      fs_give((void **) &raw_ctxt);
	}
	else{
	    q_status_message(SM_ORDER|SM_DING, 3, 3,
			     "Programmer botch in context_config_edit");
	    return(0);
	}

	return(15);
    }

    ps->mangled_screen = 1;
    return(0);
}
Esempio n. 21
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);
}
Esempio n. 22
0
/*
 * Manage the display list cache.
 *
 * The cache is a circular array of DL_CACHE_S elements.  It always
 * contains a contiguous set of display lines.
 * The lowest numbered line in the cache is
 * valid_low, and the highest is valid_high.  Everything in between is
 * also valid.  Index_of_low is where to look
 * for the valid_low element in the circular array.
 *
 * We make calls to dlc_prev and dlc_next to get new entries for the cache.
 * We need a starting value before we can do that.
 *
 * This returns a pointer to a dlc for the desired row.  If you want the
 * actual display list line you call dlist(row) instead of dlc_mgr.
 */
DL_CACHE_S *
dlc_mgr(long int row, DlMgrOps op, DL_CACHE_S *dlc_start)
{
    int                new_index, known_index, next_index;
    DL_CACHE_S        *dlc = (DL_CACHE_S *)NULL;
    long               next_row;
    long               prev_row;


    if(op == Lookup){

	if(row >= valid_low && row <= valid_high){  /* already cached */

	    new_index = ((row - valid_low) + index_of_low) % size_of_cache;
	    dlc = &cache_array[new_index];

	}
	else if(row > valid_high){  /* row is past where we've looked */

	    known_index =
	      ((valid_high - valid_low) + index_of_low) % size_of_cache;
	    next_row    = valid_high + 1L;

	    /* we'll usually be looking for row = valid_high + 1 */
	    while(next_row <= row){

		new_index = (known_index + 1) % size_of_cache;

		dlc =
		  dlc_next(&cache_array[known_index], &cache_array[new_index]);

		/*
		 * This means somebody changed the file out from underneath
		 * us.  This would happen if dlc_next needed to ask for an
		 * abe to figure out what the type of the next row is, but
		 * adrbk_get_ae returned a NULL.  I don't think that can
		 * happen, but if it does...
		 */
		if(dlc->type == DlcNotSet){
		    dprint((1, "dlc_next returned DlcNotSet\n"));
		    goto panic_abook_corrupt;
		}

		if(n_cached == size_of_cache){ /* replaced low cache entry */
		    valid_low++;
		    index_of_low = (index_of_low + 1) % size_of_cache;
		}
		else
		  n_cached++;

		valid_high++;

		next_row++;
		known_index = new_index; /* for next time through loop */
	    }
	}
	else if(row < valid_low){  /* row is back up the screen */

	    known_index = index_of_low;
	    prev_row = valid_low - 1L;

	    while(prev_row >= row){

		new_index = (known_index - 1 + size_of_cache) % size_of_cache;
		dlc =
		  dlc_prev(&cache_array[known_index], &cache_array[new_index]);

		if(dlc->type == DlcNotSet){
		    dprint((1, "dlc_prev returned DlcNotSet (1)\n"));
		    goto panic_abook_corrupt;
		}

		if(n_cached == size_of_cache) /* replaced high cache entry */
		  valid_high--;
		else
		  n_cached++;

		valid_low--;
		index_of_low =
			    (index_of_low - 1 + size_of_cache) % size_of_cache;

		prev_row--;
		known_index = new_index;
	    }
	}
    }
    else if(op == Initialize){

	n_cached = 0;

	if(!cache_array || size_of_cache != 3 * MAX(as.l_p_page,1)){
	    if(cache_array)
	      free_cache_array(&cache_array, size_of_cache);

	    size_of_cache = 3 * MAX(as.l_p_page,1);
	    cache_array =
		(DL_CACHE_S *)fs_get(size_of_cache * sizeof(DL_CACHE_S));
	    memset((void *)cache_array, 0, size_of_cache * sizeof(DL_CACHE_S));
	}

	/* this will return NULL below and the caller should ignore that */
    }
    /*
     * Flush all rows for a particular addrbook entry from the cache, but
     * keep the cache alive and anchored in the same place.  The particular
     * entry is the one that dlc_start is one of the rows of.
     */
    else if(op == FlushDlcFromCache){
	long low_entry;

	next_row = dlc_start->global_row - 1;
	for(; next_row >= valid_low; next_row--){
	    next_index = ((next_row - valid_low) + index_of_low) %
		size_of_cache;
	    if(!dlc_siblings(dlc_start, &cache_array[next_index]))
		break;
	}

	low_entry = next_row + 1L;

	/*
	 * If low_entry now points one past a ListBlankBottom, delete that,
	 * too, since it may not make sense anymore.
	 */
	if(low_entry > valid_low){
	    next_index = ((low_entry -1L - valid_low) + index_of_low) %
		size_of_cache;
	    if(cache_array[next_index].type == DlcListBlankBottom)
		low_entry--;
	}

	if(low_entry > valid_low){ /* invalidate everything >= this */
	    n_cached -= (valid_high - (low_entry - 1L));
	    valid_high = low_entry - 1L;
	}
	else{
	    /*
	     * This is the tough case.  That entry was the first thing cached,
	     * so we need to invalidate the whole cache.  However, we also
	     * need to keep at least one thing cached for an anchor, so
	     * we need to get the dlc before this one and it should be a
	     * dlc not related to this same addrbook entry.
	     */
	    known_index = index_of_low;
	    prev_row = valid_low - 1L;

	    for(;;){

		new_index = (known_index - 1 + size_of_cache) % size_of_cache;
		dlc =
		  dlc_prev(&cache_array[known_index], &cache_array[new_index]);

		if(dlc->type == DlcNotSet){
		    dprint((1, "dlc_prev returned DlcNotSet (2)\n"));
		    goto panic_abook_corrupt;
		}

		valid_low--;
		index_of_low =
			    (index_of_low - 1 + size_of_cache) % size_of_cache;

		if(!dlc_siblings(dlc_start, dlc))
		  break;

		known_index = new_index;
	    }

	    n_cached = 1;
	    valid_high = valid_low;
	}
    }
    /*
     * We have to anchor ourselves at a first element.
     * Here's how we start at the top.
     */
    else if(op == FirstEntry){
	initialize_dlc_cache();
	n_cached++;
	dlc = &cache_array[0];
	dlc = get_global_top_dlc(dlc);
	dlc->global_row = row;
	index_of_low = 0;
	valid_low    = row;
	valid_high   = row;
    }
    /* And here's how we start from the bottom. */
    else if(op == LastEntry){
	initialize_dlc_cache();
	n_cached++;
	dlc = &cache_array[0];
	dlc = get_global_bottom_dlc(dlc);
	dlc->global_row = row;
	index_of_low = 0;
	valid_low    = row;
	valid_high   = row;
    }
    /*
     * And here's how we start from an arbitrary position in the middle.
     * We root the cache at display line row, so it helps if row is close
     * to where we're going to be starting so that things are easy to find.
     * The dl that goes with line row is dl_start from addrbook number
     * adrbk_num_start.
     */
    else if(op == ArbitraryStartingPoint){
	AddrScrn_Disp      dl;

	initialize_dlc_cache();
	n_cached++;
	dlc = &cache_array[0];
	/*
	 * Save this in case fill_in_dl_field needs to free the text
	 * it points to.
	 */
	dl = dlc->dl;
	*dlc = *dlc_start;
	dlc->dl = dl;
	dlc->global_row = row;

	index_of_low = 0;
	valid_low    = row;
	valid_high   = row;
    }
    else if(op == DoneWithCache){

	n_cached = 0;
	if(cache_array)
	  free_cache_array(&cache_array, size_of_cache);
    }

    return(dlc);

panic_abook_corrupt:
    q_status_message(SM_ORDER | SM_DING, 5, 10,
	_("Addrbook changed unexpectedly, re-syncing..."));
    dprint((1,
	_("addrbook changed while we had it open?, re-sync\n")));
    dprint((2,
	"valid_low=%ld valid_high=%ld index_of_low=%d size_of_cache=%d\n",
	valid_low, valid_high, index_of_low, size_of_cache));
    dprint((2,
	"n_cached=%d new_index=%d known_index=%d next_index=%d\n",
	n_cached, new_index, known_index, next_index));
    dprint((2,
	"next_row=%ld prev_row=%ld row=%ld\n", next_row, prev_row, row));
    /* jump back to a safe starting point */
    longjmp(addrbook_changed_unexpectedly, 1);
    /*NOTREACHED*/
}
Esempio n. 23
0
char *
rd_metadata_name(void)
{
    char        *p, *q, *metafile;
    char         path[MAXPATH], pinerc_dir[MAXPATH];
    struct variable *vars = ps_global->vars;

    dprint((9, "rd_metadata_name\n"));

    pinerc_dir[0] = '\0';
    if(ps_global->pinerc){
	char *prcn = ps_global->pinerc;
	char *lc;

	if((lc = last_cmpnt(prcn)) != NULL){
	    int to_copy;

	    to_copy = (lc - prcn > 1) ? (lc - prcn - 1) : 1;
	    strncpy(pinerc_dir, prcn, MIN(to_copy, sizeof(pinerc_dir)-1));
	    pinerc_dir[MIN(to_copy, sizeof(pinerc_dir)-1)] = '\0';
	}
	else{
	    pinerc_dir[0] = '.';
	    pinerc_dir[1] = '\0';
	}
    }

    /*
     * If there is no metadata file specified in the pinerc, create a filename.
     */
    if(!(VAR_REMOTE_ABOOK_METADATA && VAR_REMOTE_ABOOK_METADATA[0])){
	if(pinerc_dir[0] && (p = tempfile_in_same_dir(ps_global->pinerc,
						      meta_prefix, NULL))){
	    /* fill in the pinerc variable */
	    q = p + strlen(pinerc_dir) + 1;
	    set_variable(V_REMOTE_ABOOK_METADATA, q, 1, 0, Main);
	    dprint((2, "creating name for metadata file: %s\n",
		   q ? q : "?"));

	    /* something's broken, return NULL rab */
	    if(!VAR_REMOTE_ABOOK_METADATA || !VAR_REMOTE_ABOOK_METADATA[0]){
		our_unlink(p);
		fs_give((void **)&p);
		return(NULL);
	    }

	    fs_give((void **)&p);
	}
	else{
	    q_status_message(SM_ORDER, 3, 5,
		"can't create metadata file in pinerc directory, continuing");
	    return(NULL);
	}
    }

    build_path(path, pinerc_dir ? pinerc_dir : NULL,
	       VAR_REMOTE_ABOOK_METADATA, sizeof(path));
    metafile = path;

    /*
     * If the metadata file doesn't exist, create it.
     */
    if(can_access(metafile, ACCESS_EXISTS) != 0){
	int fd;

	if((fd = our_open(metafile, O_CREAT|O_EXCL|O_WRONLY|O_BINARY, 0600)) < 0){

	    set_variable(V_REMOTE_ABOOK_METADATA, NULL, 1, 0, Main);

	    q_status_message2(SM_ORDER, 3, 5,
		       "can't create cache file %.200s, continuing (%.200s)",
		       metafile, error_description(errno));

	    dprint((2, "can't create metafile %s: %s\n",
		       metafile ? metafile : "?", error_description(errno)));

	    return(NULL);
	}

	dprint((2, "created metadata file: %s\n",
	       metafile ? metafile : "?"));

	(void)close(fd);
    }

    return(cpystr(metafile));;
}
Esempio n. 24
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;
        }
    }
}
Esempio n. 25
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
}
Esempio n. 26
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 */
}
Esempio n. 27
0
int
select_from_list_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
{
    CONF_S *ctmp;
    int     retval = 0;

    switch(cmd){
      case MC_SELECT :
	if(*(*cl)->d.l.listmode == SingleMode){
	    (*cl)->d.l.lsel->selected = 1;
	    retval = 3;
	}
	else{
	    /* check if anything is selected */
	    /* go to first line */
	    for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
	      ;
	    
	    for(; ctmp; ctmp = next_confline(ctmp))
	      if(!(ctmp->flags & CF_NOSELECT) && ctmp->d.l.lsel->selected){
		  retval = 3;
		  break;
	      }
	    
	    if(retval == 0){
		q_status_message(SM_ORDER, 0, 3,
		     _("Nothing selected, use Exit to exit without a selection."));
	    }
	}

	break;

      case MC_LISTMODE :
        if(*(*cl)->d.l.listmode == SingleMode){
	    /*
	     * UnHide the checkboxes
	     */

	    *(*cl)->d.l.listmode = ListMode;

	    /* go to first line */
	    for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
	      ;
	    
	    for(; ctmp; ctmp = next_confline(ctmp))
	      if(!(ctmp->flags & CF_NOSELECT) && ctmp->value){
		  ctmp->value[0] = '[';
		  ctmp->value[1] = ctmp->d.l.lsel->selected ? 'X' : SPACE;
		  ctmp->value[2] = ']';
		  ctmp->keymenu  = &sel_from_list_lm;
	      }
	}
	else{
	    /*
	     * Hide the checkboxes
	     */

	    *(*cl)->d.l.listmode = SingleMode;

	    /* go to first line */
	    for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
	      ;
	    
	    for(; ctmp; ctmp = next_confline(ctmp))
	      if(!(ctmp->flags & CF_NOSELECT) && ctmp->value){
		  ctmp->value[0] = ctmp->value[1] = ctmp->value[2] = SPACE;
		  ctmp->keymenu  = &sel_from_list_sm;
	      }
	}

	ps->mangled_body = ps->mangled_footer = 1;
	break;

      case MC_TOGGLE :
	if((*cl)->value[1] == 'X'){
	    (*cl)->d.l.lsel->selected = 0;
	    (*cl)->value[1] = SPACE;
	}
	else{
	    (*cl)->d.l.lsel->selected = 1;
	    (*cl)->value[1] = 'X';
	}

	ps->mangled_body = 1;
	break;

      case MC_EXIT :
        retval = simple_exit_cmd(flags);
	break;

      default:
	retval = -1;
	break;
    }

    if(retval > 0)
      ps->mangled_body = 1;

    return(retval);
}
Esempio n. 28
0
/*
 * Given a list of entries, present them to user so user may
 * select one.
 *
 * Args  head -- The head of the list of results
 *       orig -- The string the user was searching for
 *     result -- Returned pointer to chosen LDAP_SEARCH_WINNER or NULL
 *     wp_err -- Error handling
 *      style -- 
 *
 * Returns  0   ok
 *         -1   Exit chosen by user
 *         -2   None of matched entries had an email address
 *         -3   No matched entries
 *         -4   Goback to Abook List chosen by user
 *         -5   caller shouldn't free head
 */
int
ask_user_which_entry(LDAP_SERV_RES_S *head, char *orig, LDAP_CHOOSE_S **result,
		     WP_ERR_S *wp_err, LDAPLookupStyle style)
{
    ADDR_CHOOSE_S ac;
    char          t[200];
    int           retval;

    dprint((3, "ask_user_which(style=%s)\n",
	style == AlwaysDisplayAndMailRequired ? "AlwaysDisplayAndMailRequired" :
	  style == AlwaysDisplay ? "AlwaysDisplay" :
	    style == DisplayIfTwo ? "DisplayIfTwo" :
	      style == DisplayForURL ? "DisplayForURL" :
	        style == DisplayIfOne ? "DisplayIfOne" : "?"));

    /*
     * Set up a screen for user to choose one entry.
     */

    if(style == AlwaysDisplay || style == DisplayForURL)
      snprintf(t, sizeof(t), "SEARCH RESULTS INDEX");
    else{
	int len;

	len = strlen(orig);
	snprintf(t, sizeof(t), _("SELECT ONE ADDRESS%s%s%s"),
		(orig && *orig && len < 40) ? " FOR \"" : "",
		(orig && *orig && len < 40) ? orig : "",
		(orig && *orig && len < 40) ? "\"" : "");
    }

    memset(&ac, 0, sizeof(ADDR_CHOOSE_S));
    ac.title = cpystr(t);
    ac.res_head = head;

    retval = ldap_addr_select(ps_global, &ac, result, style, wp_err, orig);

    switch(retval){
      case 0:		/* Ok */
	break;

      case -1:		/* Exit chosen by user */
	wp_exit = 1;
	break;

      case -4:		/* GoBack to AbookList chosen by user */
	break;

      case -5:
	wp_nobail = 1;
	break;

      case -2:
	if(style != AlwaysDisplay){
	    if(wp_err->error)
	      fs_give((void **)&wp_err->error);

	    wp_err->error =
   cpystr(_("None of the names matched on directory server has an email address"));
	    q_status_message(SM_ORDER, 3, 5, wp_err->error);
	    display_message('x');
	}

	break;

      case -3:
	if(style == AlwaysDisplayAndMailRequired){
	    if(wp_err->error)
	      fs_give((void **)&wp_err->error);

	    wp_err->error = cpystr(_("No matches on directory server"));
	    q_status_message(SM_ORDER, 3, 5, wp_err->error);
	    display_message('x');
	}

	break;
    }

    fs_give((void **)&ac.title);

    return(retval);
}
Esempio n. 29
0
/*----------------------------------------------------------------------
        Read a character from keyboard with timeout
 Input:  none

 Result: Returns command read via read_char
         Times out and returns a null command every so often

  Calculates the timeout for the read, and does a few other house keeping 
things.  The duration of the timeout is set in pine.c.
  ----------------------------------------------------------------------*/
UCS
read_command(char **utf8str)
{
    int tm = 0, more_freq_timeo;
    UCS ucs;
    long dtime; 
    static unsigned char utf8buf[7];
    unsigned char *newdestp;

    /*
     * timeo is the mail-check-interval. What we want to do (ignoring the
     * messages_queued part) is timeout more often than timeo but only
     * check for new mail every timeo or so seconds. The reason we want to
     * timeout more often is so that we will have a chance to catch the user
     * in an idle period where we can do a check_point(). Otherwise, with
     * a default mail-check-interval, we are almost always calling newmail
     * right after the user presses a key, making it the worst possible
     * time to do a checkpoint.
     */

    more_freq_timeo = MIN(get_input_timeout(), IDLE_TIMEOUT);
    if(more_freq_timeo == 0)
      more_freq_timeo = IDLE_TIMEOUT;

    cancel_busy_cue(-1);
    tm = (messages_queued(&dtime) > 1) ? (int)dtime : more_freq_timeo;

    if(utf8str)
      *utf8str = NULL;

    ucs = read_char(tm);
    if(ucs != NO_OP_COMMAND && ucs != NO_OP_IDLE && ucs != KEY_RESIZE)
      zero_new_mail_count();

#ifdef	BACKGROUND_POST
    /*
     * Any expired children to report on?
     */
    if(ps_global->post && ps_global->post->pid == 0){
	int   winner = 0;

	if(ps_global->post->status < 0){
	    q_status_message(SM_ORDER | SM_DING, 3, 3, "Abysmal failure!");
	}
	else{
	    (void) pine_send_status(ps_global->post->status,
				    ps_global->post->fcc, tmp_20k_buf, SIZEOF_20KBUF,
				    &winner);
	    q_status_message(SM_ORDER | (winner ? 0 : SM_DING), 3, 3,
			     tmp_20k_buf);

	}

	if(!winner)
	  q_status_message(SM_ORDER, 0, 3,
	  "Re-send via \"Compose\" then \"Yes\" to \"Continue INTERRUPTED?\"");

	if(ps_global->post->fcc)
	  fs_give((void **) &ps_global->post->fcc);

	fs_give((void **) &ps_global->post);
    }
#endif

    /*
     * The character we get from read_char() is a UCS-4 char. Or it could be a special
     * value like KEY_UP or NO_OP_IDLE or something similar. From here on out
     * we're going to operate with UTF-8 internally. This is the point where we
     * convert the UCS-4 input (actually whatever sort of input the user is typing
     * was converted to UCS-4 first) to UTF-8. It's easy in this read_command
     * case because if user types a non-ascii character as a command it's going to be
     * an error. All commands are ascii. In order to present a reasonable error
     * message we pass back the UTF-8 string to the caller.
     */
    if(ucs >= 0x80 && ucs < KEY_BASE){
	/*
	 * User typed a character that is non-ascii. Convert it to
	 * UTF-8.
	 */
	memset(utf8buf, 0, sizeof(utf8buf));
	newdestp = utf8_put(utf8buf, (unsigned long) ucs);
	if(newdestp - utf8buf > 1){	/* this should happen */
	    if(utf8str)
	      *utf8str = (char *) utf8buf;

	    dprint((9, "Read command: looks like user typed non-ascii command 0x%x %s: returning KEY_UTF8\n", ucs, pretty_command(ucs)));
	    ucs = KEY_UTF8;
	}
	else{
	    dprint((9, "Read command: looks like user typed unknown, non-ascii command 0x%x %s: returning KEY_UNKNOWN\n", ucs, pretty_command(ucs)));
	    ucs = KEY_UNKNOWN;	/* best we can do, shouldn't happen */
	}
    }
    else{
	dprint((9, "Read command returning: 0x%x %s\n", ucs, pretty_command(ucs)));
    }

    return(ucs);
}
Esempio n. 30
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 */
}