📄 cmds.c
字号:
#ifndef lint#ifdef sccsstatic char sccsid[] = "@(#)cmds.c 1.1 92/07/30 Copyr 1987 Sun Micro";#endif#endif/* * Copyright (c) 1987 by Sun Microsystems, Inc. *//* * Mailtool - tool command handling *//*************************************************************** ******* ******* ****** NOTE: please use the comment section at the end ****** ****** of the program to document source changes. ****** ******* ******* ***************************************************************/ #include <stdio.h>#include <errno.h>#include <signal.h>#include <ctype.h>#include <vfork.h>#include <sunwindow/window_hs.h>#include <sys/stat.h>#include <sys/types.h>#include <sundev/kbd.h>#include <fcntl.h>#include <suntool/window.h>#include <suntool/frame.h>#include <suntool/panel.h>#include <suntool/text.h>#include <suntool/walkmenu.h>#include <suntool/scrollbar.h>#include <suntool/selection.h>#include <suntool/selection_svc.h>#include <suntool/selection_attributes.h>#include <suntool/alert.h>#include "glob.h"#include "tool.h"/* performance: global cache of getdtablesize() */extern int dtablesize_cache;#define GETDTABLESIZE() \ (dtablesize_cache?dtablesize_cache:(dtablesize_cache=getdtablesize()))#define PRIMARY_PD_SELECTION 0x0010 #define PRIMARY_SELECTION 0x0001 char *strcpy(), *sprintf(), *strcat();static char *fields[] = {"|>recipients<|", "|>subject<|", "|>body of message<|", "|>other recipients<|", "|>blind carbon copies<|", 0};static char *mt_get_command_string(), *mt_find_command_string();Menu mt_file_menu; /* menu of most recent file names used. * Behind File: panel item */static void mt_create_cmd_panel(), mt_do_del(), mt_do_deliver(); static void mt_do_retrieve(), mt_do_save(), mt_set_nomail();static int mt_has_selection();static void mt_yield_all();static Seln_holder seln_holder;/* notify procs, in alphabetical order *//* * Abort the tool. *//* ARGSUSED */voidmt_abort_proc(item, ie) Panel_item item; Event *ie;{ (void)win_release_event_lock(mt_cmdpanel_fd); mt_yield_all(); mt_aborting = TRUE; if (event_ctrl_is_down(ie)) mt_assign("expert", ""); /* XXX - force no confirm, just quit */ (void)window_done((struct tool *)(LINT_CAST(mt_frame))); /* Should free window */}/* * "Quietly" retrieves new mail, i.e.., does not scroll headersw or update * message sw. Does commit if more than specified number of messages have * been deleted. Used for auto-reading. See mt_itimer in tool.c */voidmt_auto_retrieve_mail_proc(item, ie) Panel_item item; Event *ie;{ char *p; p = mt_value("commitfrequency"); mt_do_retrieve(item, ie, (!p || mt_del_count <= atoi(p)), TRUE);}/* * Cancel the current reply (or send, or forward). *//* ARGSUSED */voidmt_cancel_proc(item, ie) Panel_item item; Event *ie;{ Panel panel; struct reply_panel_data *ptr; char scratch[256]; panel = panel_get(item, PANEL_PARENT_PANEL); ptr = (struct reply_panel_data *)panel_get(panel, PANEL_CLIENT_DATA); if (!(event_ctrl_is_down(ie)) && window_get(ptr->replysw, TEXTSW_MODIFIED) && (ptr->behavior == mt_Stay_Up ? !mt_confirm(ptr->replysw, FALSE, FALSE, "Confirm", "Do NOT clear window", "Are you sure you want to Clear window?", 0) : !mt_confirm(ptr->replysw, FALSE, FALSE, "Confirm", "Do NOT cancel window", "Are you sure you want to Cancel window?", 0) )) return; if (mt_value("save")) { char *s; FILE *f; s = mt_value("DEAD"); /* * (Bug# 1014141 fix) added code to recognise * "/dev/null" and not to save to it. */ if (strcmp(s,"/dev/null") != 0) { if (s == NULL || *s == '\0') s = "~/dead.letter"; mt_full_path_name(s, scratch); if (f = mt_fopen(scratch, "w")) { /* check to see if can write to this file */ (void) fclose(f); (void) textsw_store_file(ptr->replysw, scratch, 0, 0); } } } textsw_reset(ptr->replysw, 0, 0); (void) unlink(ptr->replysw_file); ptr->inuse = FALSE; if (ptr->frame != mt_frame) (void) window_set(ptr->frame, FRAME_ICON, &mt_empty_letter_icon, 0); if (ptr->behavior == mt_Disappear) mt_stop_reply(ptr); else if (ptr->behavior == mt_Close) (void) window_set(ptr->frame, FRAME_CLOSED, TRUE, 0);}/*/* * Change Mail's working directory. *//* ARGSUSED */voidmt_cd_proc(item, ie) Panel_item item; Event *ie;{ char *dir; if (mt_dir_item == NULL) { mt_create_cd_popup(); return; } dir = (char *)panel_get_value(mt_dir_item); if (dir == NULL) dir = "~"; if (strcmp(dir, mt_wdir) == 0) return; mt_mail_cmd("echo \"%s\"", dir); mt_info[strlen(mt_info) - 1] = '\0'; if (chdir(mt_info) < 0) { extern int errno; extern int sys_nerr; extern char *sys_errlist[]; if (errno < sys_nerr) (void) sprintf(mt_info, "cd: %s", sys_errlist[errno]); else (void) sprintf(mt_info, "cd: errno=%d", errno); mt_warn(mt_frame, mt_info, 0); } else { mt_set_mailwd(mt_info); (void) strcpy(mt_wdir, dir); mt_update_info(""); } if (mt_cd_frame) mt_destroy_cd_popup();}/* * Commit the current set of changes. *//* ARGSUSED */voidmt_commit_proc(item, ie) Panel_item item; Event *ie;{ static u_long last; u_long when; when = event_time(ie).tv_sec; if (last != 0 && when < last) { /* * this event occurred BEFORE the last commit operation * completed, i.e., user bounced on the key */ last = when; return; } if (mt_nomail && mt_delp == NULL) { mt_warn(mt_frame, "No Mail", 0); return; } (void)win_release_event_lock(mt_cmdpanel_fd); mt_yield_all(); /* use mt_yield_all() to save shelf */ if (strcmp(mt_folder, mt_mailbox) == 0) mt_new_folder("%", FALSE, FALSE); else mt_new_folder(mt_folder, FALSE, FALSE); last = mt_current_time();}/* Compose a new mail message. */voidmt_comp_proc(item, ie) Panel_item item; Event *ie;{ struct reply_panel_data *ptr; int msg, orig; int lower_context; if (!(ptr = mt_get_replysw(item))) return; msg = 0; orig = event_ctrl_is_down(ie); if (orig && (msg = mt_get_curselmsg(0)) == 0) return; mt_save_curmsg(); if (!(mt_compose_msg(msg, ptr->replysw_file, mt_value("askcc") ? !event_shift_is_down(ie) : event_shift_is_down(ie), orig))) return; mt_start_reply(ptr); lower_context = (int)window_get(ptr->replysw, TEXTSW_LOWER_CONTEXT); (void) window_set(ptr->replysw, TEXTSW_LOWER_CONTEXT, -1, /* work around to * suppress scrolling as * you insert */ TEXTSW_FILE_CONTENTS, ptr->replysw_file, TEXTSW_LOWER_CONTEXT, lower_context, 0); (void) window_set(ptr->replysw, TEXTSW_INSERTION_POINT, 4, 0); /* after "To: " */ if (mt_use_fields) { Textsw_index first, last_plus_one; first = (Textsw_index)window_get(ptr->replysw, TEXTSW_INSERTION_POINT); textsw_match_bytes(ptr->replysw, &first, &last_plus_one, "|>", 2, "<|", 2, TEXTSW_FIELD_FORWARD); (void) textsw_set_selection(ptr->replysw, first, last_plus_one, PRIMARY_SELECTION | PRIMARY_PD_SELECTION); (void) window_set(ptr->replysw, TEXTSW_INSERTION_POINT, last_plus_one, 0); } mt_display_reply(ptr); if (ptr->frame != mt_frame) (void) window_set(ptr->frame, FRAME_ICON, &mt_composing_icon, 0); if ((nfds_avail()) < 4) { /* * currently, you * need 4 (choke!) fds to invoke a filter, two for each pair * of pipes */ mt_warn(window_get(ptr->replysw, WIN_OWNER), "Warning: low on fds. Don't use text filters", "or the text extras menu in composition windows.", 0); } if (mt_debugging) { (void) printf("replysw setup, #fds = %d\n", nfds_avail()); (void) fflush(stdout); }}/* * Copy the selected message to the specified file. *//* ARGSUSED */voidmt_copy_proc(item, ie) Panel_item item; Event *ie;{ mt_do_save(0, ie, mt_has_selection());}/* Delete the current message and display the next message. *//* ARGSUSED */voidmt_del_proc(item, ie) Panel_item item; Event *ie;{ int msg; int has_selection; char *p; if (mt_nomail) { mt_warn(mt_frame, "No Mail", 0); return; } if ((msg = mt_get_curselmsg(0)) == 0) return; has_selection = mt_has_selection(); mt_yield_all(); /* use mt_yield_all() to save shelf */ if ((p = mt_value("trash")) || msg != mt_curmsg) { /* no need to save current message if no trash folder */ mt_save_curmsg(); if (p) (void)mt_copy_msg(msg, p); } mt_do_del(msg, ie, has_selection);}/* * Actually send the current reply-type message. *//* ARGSUSED */voidmt_deliver_proc(item, ie) Panel_item item; Event *ie;{ mt_do_deliver(item, ie);}/* Saves the shelf before before yeilding /* * Actually send the current reply-type message, but leave window intact. *//* ARGSUSED */voidmt_deliver_intact_proc(item, ie) Panel_item item; Event *ie;{ mt_do_deliver(item, ie);}/* * Yield all selections to Selection Service. Use when exiting or * undertaking a lengthy process where the program * will be unable to respond to requests concerning selections held. * * (bug# 1011496 & bug# 1009592 fix) * Routine also saves the current shelf (clipboard) with seln_hold_file(), * even if mailtool exits completely. */static voidmt_yield_all(){ Seln_holder holder; holder = seln_inquire(SELN_SHELF); if (holder.state != SELN_NONE) /* if clipboard has something */ { int fd; Seln_request *request; /* get ASCII contents of shelf, limit 2000 bytes */ request = seln_ask(&holder, SELN_REQ_CONTENTS_ASCII, 0, 0); if (request->status == SELN_FAILED) (void) fputs("Unable to get & save shelf contents\n", stderr); else if ((fd = open(mt_clipboard, (O_RDWR | O_TRUNC))) != -1) { /* * The 1st 4 bytes of the data buffer contain info to * identify that a shelf has been returned. Write out * the ASCII contents minus the 4 bytes into the opened * file, then close the file. */ (void) write(fd, &request->data[4], strlen(request->data)-4); (void) close(fd); /* tell the selection service to use file contents for shelf */ if ((seln_hold_file(SELN_SHELF, mt_clipboard)) != SELN_SUCCESS) (void) fprintf(stderr,"Cannot get shelf in %s\n",mt_clipboard); } else (void) fprintf(stderr,"Cannot open %s to save shelf\n",mt_clipboard); } seln_yield_all();}/* * Done with the current folder, close the tool. *//* ARGSUSED */voidmt_done_proc(item, ie) Panel_item item; Event *ie;{ char *p; mt_save_curmsg(); /* * Since a commit has been made, check to see if the header array can * be reduced in size. */ if ((mt_maxmsg-mt_del_count) <= (current_size-INCR_SIZE)) { if((mt_message=(struct msg *)realloc((struct msg *)mt_message, (unsigned)(sizeof(struct msg)*(current_size-INCR_SIZE)))) == NULL) { fprintf(stderr,"Realloc failed to decrement storage\n"); exit(1); } else current_size -= INCR_SIZE; } (void) window_set(mt_frame, FRAME_CLOSED, TRUE, 0); (void) win_post_id(mt_frame, WIN_RESIZE, NOTIFY_IMMEDIATE); (void) win_post_id(mt_frame, WIN_REPAINT, NOTIFY_IMMEDIATE); mt_tool_is_busy(TRUE, "going idle..."); if (mt_open_menu_item) (void) menu_set(mt_open_menu_item, MENU_PULLRIGHT, mt_open_menu_pullright, 0); (void) win_release_event_lock(mt_cmdpanel_fd); mt_yield_all(); if (!mt_idle_mail()) { /* can fail if can't problems writing to /tmp */ mt_tool_is_busy(FALSE); return; } mt_idle = TRUE; mt_load_from_folder = NULL; (void) strcpy(mt_folder, "[None]"); mt_set_nomail(); if (p = mt_value("trash")) mt_del_folder(p); mt_tool_is_busy(FALSE);}/* * Switch to the specified folder. *//* ARGSUSED */voidmt_folder_proc(item, ie) Panel_item item; Event *ie;{ char *file; static u_long last; u_long when; when = event_time(ie).tv_sec; /* * (Bug# 1009020 fix) when mailtool is iconic and the user opens * the tool into a particular folder, the above line will set to * "when = 0". I added that check below so mailtool will not * abort the loading of a folder from the iconic state. */ if (when != 0 && last != 0 && when < last ) { /* * this event occurred BEFORE the last folder operation * completed, i.e., user bounced on the key */ last = when; return; } (void)win_release_event_lock(mt_cmdpanel_fd); file = (char *)panel_get_value(mt_file_item); if (file == NULL || *file == '\0') { mt_warn(mt_frame, "Must specify file name.", 0); return; } mt_save_filename(file); mt_new_folder(file, FALSE, FALSE); last = mt_current_time();}/* * Include the selected message in the message composition window. *//* ARGSUSED */voidmt_include_proc(item, ie) Panel_item item; Event *ie;{ Frame frame; struct reply_panel_data *ptr; int msg; Textsw_status status; if (mt_nomail) { mt_warn(mt_frame, "No Mail", 0); return; } else if ((msg = mt_get_curselmsg(0)) == 0) /* warning displayed in mt_get_curselmsg */ return; ptr = (struct reply_panel_data *)panel_get( panel_get(item, PANEL_PARENT_PANEL), PANEL_CLIENT_DATA); frame = window_get(ptr->replysw, WIN_OWNER); mt_save_curmsg(); if (!(mt_include_msg(msg, mt_scratchfile, event_ctrl_is_down(ie)))) return; (void) window_set(ptr->replysw, TEXTSW_STATUS, &status, TEXTSW_INSERT_FROM_FILE, mt_scratchfile, 0); if (status == TEXTSW_STATUS_OUT_OF_MEMORY) mt_warn(frame, "Insertion failed: memory buffer exceeded.", "You can get around this by undoing the Include,", "using the text menu to store the contents of the", "message composition window to a file, and then", "redoing the include. Or, you can enlarge the size", "of the memory buffer by using defaultsedit to", "increase the default value of \'memorymaximum\'", "quitting mailtool, and starting again.", 0); /* * this copies the bytes, so don't have to worry about overwriting * scratch file if more than one include. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -