1 /*
2  |	This is the source for hbiff, a program that monitors an
3  |	electronic mailbox.  It is provided as is.  No warranties
4  |	implied or otherwise are made, nor are any claims as to its
5  |	usefulness for any purpose.
6  |
7  |	$Source: /users/lamont/src/cmd/hbiff/RCS/hbiff.c,v $
8  |	$Author: lamont $
9  |	$State: Exp $  $Locker:  $
10  |	$Date: 92/09/15 15:01:05 $
11  */
12 
13 
14 char ident[] = "@(#)hbiff: $Revision: 1.2 $";	/* what string, version info	*/
15 
16 #define TRUE 1
17 #define FALSE 0
18 #include <stdio.h>
19 #include <unistd.h>
20 #include <pwd.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <sys/file.h>
24 #include <X11/Xlib.h>
25 #include <X11/Xutil.h>
26 #include <string.h>
27 #include <signal.h>
28 #include <time.h>
29 #include <utime.h>
30 #include <errno.h>
31 
32 extern int errno;
33 
34 #define MASK(f) (1 << (f))
35 
36 #define max(a, b) ((a) > (b) ? (a) : (b))
37 
38 #define nomail_width 64
39 #define nomail_height 64
40 static char nomail_bits[] = {
41  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
42  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
43  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
44  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
45  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
46  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
47  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
48  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0x7f,0x00,
49  0x00,0x00,0x08,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0xe4,0x00,0x00,0x00,0x80,
50  0x00,0x00,0x00,0xb4,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x5c,0x71,0x1c,0x00,
51  0x00,0x01,0x00,0x00,0xac,0x62,0x0c,0x02,0x00,0x03,0x00,0x00,0x5c,0xa3,0x0a,
52  0xc5,0x09,0x02,0x00,0x00,0xac,0x22,0x89,0x88,0x08,0x02,0x00,0x00,0x5c,0x23,
53  0x89,0x88,0x08,0x02,0x00,0x00,0xac,0x22,0x88,0x8f,0x08,0x02,0x00,0x00,0x5c,
54  0x23,0x88,0x88,0x48,0x02,0x00,0x00,0xac,0x22,0x88,0x88,0x38,0x02,0x00,0x00,
55  0x5c,0x23,0x88,0xc8,0x01,0x02,0x00,0x00,0xac,0x22,0x88,0x1c,0x80,0x03,0x00,
56  0x00,0x5c,0x23,0xc8,0x01,0xf0,0x00,0x00,0x00,0xac,0x22,0x1c,0x00,0x0e,0x00,
57  0x00,0x00,0x58,0x73,0x00,0xe0,0x01,0x00,0x00,0x00,0xb2,0x02,0x00,0x1e,0x00,
58  0x00,0x00,0x00,0x67,0x03,0xf0,0x03,0x00,0x00,0x00,0x00,0xcd,0x02,0x1e,0x02,
59  0x00,0x00,0x00,0x80,0x99,0x83,0x23,0x02,0x00,0x00,0x00,0x80,0x30,0x61,0x24,
60  0x02,0x00,0x00,0x00,0xc0,0x60,0x1e,0x24,0x02,0x00,0x00,0x00,0x40,0xc0,0x00,
61  0x24,0x02,0x00,0x00,0x00,0x60,0x80,0x01,0x24,0x02,0x00,0x00,0x00,0x20,0x80,
62  0x01,0x24,0x02,0x00,0x00,0x00,0x30,0x80,0x01,0x24,0x02,0x00,0x00,0x00,0x10,
63  0x80,0x00,0x24,0x02,0x00,0x00,0x00,0x10,0xc0,0x00,0x24,0x02,0x00,0x00,0x00,
64  0x30,0x40,0x94,0x25,0x02,0x00,0x00,0x00,0x20,0x60,0x98,0x24,0x02,0x00,0x00,
65  0x00,0x60,0x30,0xb4,0x24,0x02,0x00,0x00,0x00,0xc0,0x1c,0xee,0x24,0x02,0x00,
66  0x00,0x00,0x80,0x07,0xf0,0x24,0xc2,0x00,0x00,0x00,0x00,0x00,0xa0,0x25,0x7a,
67  0x00,0x00,0x00,0x00,0x00,0x7c,0x27,0x36,0x03,0x00,0x00,0x00,0x00,0x1c,0x26,
68  0x0f,0x02,0x00,0x00,0x00,0x00,0x04,0x26,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,
69  0xa4,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0xa4,0x01,0x00,0x00,0x00,0x00,0x00,
70  0x00,0xac,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x02,0x00,0x00,0x00,0x00,
71  0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
72  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
73  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
74  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
75  0x00,0x00};
76 
77 #define newmail_width 64
78 #define newmail_height 64
79 static char newmail_bits[] = {
80  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
81  0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd0,0x01,0x00,0x00,
82  0x00,0x00,0x00,0x00,0x50,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x18,0x00,
83  0x00,0x00,0x00,0x00,0x00,0x50,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x18,
84  0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0xd0,
85  0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
86  0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x00,0x00,0x00,
87  0x00,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0x7f,0x00,
88  0x00,0x00,0x18,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0xec,0x00,0x00,0x00,0x80,
89  0x00,0x00,0x00,0xf4,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0xfe,0x73,0x1c,0x00,
90  0x00,0x01,0x00,0xfc,0xff,0x63,0x0c,0x02,0x00,0x03,0x00,0x04,0x00,0xa2,0x0a,
91  0xc5,0x09,0x02,0x00,0x64,0x82,0x23,0x89,0x88,0x08,0x02,0x00,0x04,0xd5,0x22,
92  0x89,0x88,0x08,0x02,0x00,0x08,0x38,0x23,0x88,0x8f,0x08,0x02,0x00,0xc8,0x07,
93  0x23,0x88,0x88,0x48,0x02,0x00,0x3e,0x80,0x22,0x88,0x88,0x38,0x02,0x00,0x06,
94  0x40,0x22,0x88,0xc8,0x01,0x02,0x00,0xfe,0x3f,0x22,0x88,0x1c,0x80,0x03,0x00,
95  0x02,0x00,0x22,0xc8,0x01,0xf0,0x00,0x00,0x06,0x00,0x22,0x1c,0x00,0x0e,0x00,
96  0x00,0x04,0x80,0x73,0x00,0xe0,0x01,0x00,0x00,0x04,0xf8,0x02,0x00,0x1e,0x00,
97  0x00,0x00,0x04,0x6f,0x03,0xf0,0x03,0x00,0x00,0x00,0xe4,0xcd,0x02,0x1e,0x02,
98  0x00,0x00,0x00,0x9c,0x99,0x83,0x23,0x02,0x00,0x00,0x00,0x80,0x30,0x63,0x24,
99  0x02,0x00,0x00,0x00,0xc0,0x60,0x1e,0x24,0x02,0x00,0x00,0x00,0x40,0xc0,0x00,
100  0x24,0x02,0x00,0x00,0x00,0x60,0x80,0x01,0x24,0x02,0x00,0x00,0x00,0x20,0x80,
101  0x01,0x24,0x02,0x00,0x00,0x00,0x30,0x80,0x01,0x24,0x02,0x00,0x00,0x00,0x10,
102  0x80,0x00,0x24,0x02,0x00,0x00,0x00,0x10,0xc0,0x00,0x24,0x02,0x00,0x00,0x00,
103  0x30,0x40,0x94,0x25,0x02,0x00,0x00,0x00,0x20,0x60,0x98,0x24,0x02,0x00,0x00,
104  0x00,0x60,0x30,0xb4,0x24,0x02,0x00,0x00,0x00,0xc0,0x1c,0xee,0x24,0x02,0x00,
105  0x00,0x00,0x80,0x07,0xf0,0x24,0xc2,0x00,0x00,0x00,0x00,0x00,0xa0,0x25,0x7a,
106  0x00,0x00,0x00,0x00,0x00,0x7c,0x27,0x36,0x03,0x00,0x00,0x00,0x00,0x1c,0x26,
107  0x0f,0x02,0x00,0x00,0x00,0x00,0x04,0x26,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,
108  0xa4,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0xa4,0x01,0x00,0x00,0x00,0x00,0x00,
109  0x00,0xac,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x02,0x00,0x00,0x00,0x00,
110  0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
111  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
112  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
113  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
114  0x00,0x00};
115 
116 #define oldmail_width 64
117 #define oldmail_height 64
118 static char oldmail_bits[] = {
119  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
120  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
121  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
122  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
123  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
124  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
125  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
126  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0xff,0x7f,0x00,
127  0x00,0x00,0x18,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0xec,0x00,0x00,0x00,0x80,
128  0x00,0x00,0x00,0xf4,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0xfe,0x73,0x1c,0x00,
129  0x00,0x01,0x00,0xfc,0xff,0x63,0x0c,0x02,0x00,0x03,0x00,0x04,0x00,0xa2,0x0a,
130  0xc5,0x09,0x02,0x00,0x64,0x82,0x23,0x89,0x88,0x08,0x02,0x00,0x04,0xd5,0x22,
131  0x89,0x88,0x08,0x02,0x00,0x08,0x38,0x23,0x88,0x8f,0x08,0x02,0x00,0xc8,0x07,
132  0x23,0x88,0x88,0x48,0x02,0x00,0x3e,0x80,0x22,0x88,0x88,0x38,0x02,0x00,0x06,
133  0x40,0x22,0x88,0xc8,0x01,0x02,0x00,0xfe,0x3f,0x22,0x88,0x1c,0x80,0x03,0x00,
134  0x02,0x00,0x22,0xc8,0x01,0xf0,0x00,0x00,0x06,0x00,0x22,0x1c,0x00,0x0e,0x00,
135  0x00,0x04,0x80,0x73,0x00,0xe0,0x01,0x00,0x00,0x04,0xf8,0x02,0x00,0x1e,0x00,
136  0x00,0x00,0x04,0x6f,0x03,0xf0,0x03,0x00,0x00,0x00,0xe4,0xcd,0x02,0x1e,0x02,
137  0x00,0x00,0x00,0x9c,0x99,0x83,0x23,0x02,0x00,0x00,0x00,0x80,0x30,0x63,0x24,
138  0x02,0x00,0x00,0x00,0xc0,0x60,0x1e,0x24,0x02,0x00,0x00,0x00,0x40,0xc0,0x00,
139  0x24,0x02,0x00,0x00,0x00,0x60,0x80,0x01,0x24,0x02,0x00,0x00,0x00,0x20,0x80,
140  0x01,0x24,0x02,0x00,0x00,0x00,0x30,0x80,0x01,0x24,0x02,0x00,0x00,0x00,0x10,
141  0x80,0x00,0x24,0x02,0x00,0x00,0x00,0x10,0xc0,0x00,0x24,0x02,0x00,0x00,0x00,
142  0x30,0x40,0x94,0x25,0x02,0x00,0x00,0x00,0x20,0x60,0x98,0x24,0x02,0x00,0x00,
143  0x00,0x60,0x30,0xb4,0x24,0x02,0x00,0x00,0x00,0xc0,0x1c,0xee,0x24,0x02,0x00,
144  0x00,0x00,0x80,0x07,0xf0,0x24,0xc2,0x00,0x00,0x00,0x00,0x00,0xa0,0x25,0x7a,
145  0x00,0x00,0x00,0x00,0x00,0x7c,0x27,0x36,0x03,0x00,0x00,0x00,0x00,0x1c,0x26,
146  0x0f,0x02,0x00,0x00,0x00,0x00,0x04,0x26,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,
147  0xa4,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0xa4,0x01,0x00,0x00,0x00,0x00,0x00,
148  0x00,0xac,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x02,0x00,0x00,0x00,0x00,
149  0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
150  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
151  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
152  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
153  0x00,0x00};
154 
155 #define nomail 0
156 #define newmail 1
157 #define oldmail 2
158 
159 Pixmap      pix[3];
160 
161 FILE *fp;
162 XClassHint	class_spec;
163 Display *disp_ptr;
164 GC gc;
165 GC rev_gc;
166 GC new_mail_gc;
167 GC summary_gc;
168 XGCValues gcvalues;
169 int screen;
170 Window window_id;
171 Window from_wid = 0;
172 int width, height, swidth, sheight;
173 int max_lines, max_width;
174 int lines, new_lines;
175 int x_neg, y_neg, sx_neg, sy_neg;	/* flags to indicate that x and/or y are negative */
176 int result;
177 int x, y, sx, sy, i;
178 int pix_x_offset, pix_y_offset, text_x_offset, text_y_offset;
179 int border_width;
180 char *Display_name;
181 int counter;
182 XSetWindowAttributes win_attrib;
183 unsigned long background, foreground, border;
184 unsigned long new_mail_background, new_mail_foreground;
185 unsigned long summary_background, summary_foreground;
186 XFontStruct *ae_font;
187 int fontheight, fontwidth;
188 char *bg_color, *fg_color, *b_color, *nm_bg_color, *nm_fg_color;
189 char *summary_fg_color, *summary_bg_color;
190 XColor exact_def_return, screen_def_return;
191 Colormap colormap;
192 int curr_state = 255;
193 int new_mail_raise;
194 char *username;
195 char mail_file[128];
196 char hostname[128];
197 char *mail_command;
198 char num_of_msgs[16];
199 char num_of_new[16];
200 int hostname_len;
201 int timer;
202 char *font_name;
203 int reverse_video;
204 int new_mail_reverse;
205 int new_mail_beep = TRUE;
206 int show_new_mail = FALSE;
207 int reverse_on;
208 int no_flash = FALSE;
209 int reverse_list = FALSE;
210 int new_mail_showing = FALSE;
211 int show_tally = FALSE;
212 int global_volume = 50;
213 int name_set = FALSE;
214 int file_is_dir = FALSE;
215 XSizeHints xsh, sxsh;
216 
217 XEvent	event;
218 XButtonEvent *button_event;
219 
220 int xfd, readfds;
221 int ttymask;
222 struct timeval timeout;
223 int number_of_events;
224 int child_num;
225 time_t last_hbiff_access = 0;
226 
227 int clear_child();
228 
229 struct passwd *pw;
230 
231 struct from_text {
232 	int length;		/* should include NULL character	*/
233 	char *string;		/* line of text				*/
234 	char flag;		/* flag to indicate that this is new mail */
235 	struct from_text *next;	/* next line				*/
236 	};
237 
238 struct from_text *old_msg_list = NULL, *new_msg_list = NULL;
239 
240 /*
241  |	Sound stuff borrowed from a program written by Roger Petersen
242  */
243 
244 XKeyboardControl	save_kbd;
245 
246 int argc1;
247 char **argv1;
248 
main(argc,argv)249 main(argc, argv)
250 int argc;
251 char *argv[];
252 {
253 	char	text[10];
254 	KeySym	key;
255 	int done;
256 	int temp;
257 	char buffer[512];
258 	char *temp_ptr;
259 	struct stat buf;
260 
261 	Display_name = (char *) getenv("DISPLAY");
262 /*
263  |	Check if the user specified a display on the command line
264  */
265 	for (counter=1; counter < argc; counter++)
266 	{
267 		if (!strcmp(argv[counter], "-display"))
268 		{
269 			counter++;
270 			Display_name = argv[counter];
271 		}
272 	}
273 
274 	argc1 = argc;
275 	argv1 = argv;
276 
277 /*
278  |	default mail command
279  */
280 	mail_command = "xterm -e Mail";
281 	x = 100;
282 	y = 100;
283 	sx = 50;
284 	sy = 50;
285 	x_neg = y_neg = sx_neg = sy_neg = FALSE;
286 	xsh.flags = sxsh.flags = PPosition | PSize;
287 	child_num = 0;
288 	timer = 30;
289 	border_width = 3;
290 	height = width = 0;
291 	pw = getpwuid(getuid());
292 	username = pw->pw_name;
293 	gethostname(hostname, 32);
294 	temp_ptr = hostname;
295 	while ((*temp_ptr != '\0') && (*temp_ptr != '.'))
296 		temp_ptr++;
297 	*temp_ptr = '\0';
298 	hostname_len = strlen(hostname);
299 	mail_file[0] = '\0';
300 	reverse_video = new_mail_reverse = new_mail_raise = new_mail_beep = FALSE;
301 	reverse_on = FALSE;
302 	if ((disp_ptr = XOpenDisplay(Display_name)) == 0)
303 	{
304 		fprintf(stderr, "could not open display \"%s\"\n", Display_name);
305 		exit(1);
306 	}
307 	screen = DefaultScreen(disp_ptr);
308 
309 /*
310  |	get default values from ~/.Xdefaults file
311  */
312 	get_defaults();
313 
314 /*
315  |	see what options were specified on the command line
316  */
317 	for (counter=1; counter < argc; counter++)
318 	{
319 		if (!strcmp(argv[counter], "-display"))
320 		{
321 			counter++;
322 			Display_name = argv[counter];
323 		}
324 		else if (!strcmp(argv[counter], "-fg"))
325 		{
326 			counter++;
327 			fg_color = argv[counter];
328 		}
329 		else if (!strcmp(argv[counter], "-bg"))
330 		{
331 			counter++;
332 			bg_color = argv[counter];
333 		}
334 		else if (!strcmp(argv[counter], "-bc"))
335 		{
336 			counter++;
337 			b_color = argv[counter];
338 		}
339 		else if (!strcmp(argv[counter], "-fn"))
340 		{
341 			counter++;
342 			font_name = argv[counter];
343 		}
344 		else if (!strcmp(argv[counter], "-h"))
345 		{
346 			counter++;
347 			height = atoi(argv[counter]);
348 		}
349 		else if (!strcmp(argv[counter], "-w"))
350 		{
351 			counter++;
352 			width = atoi(argv[counter]);
353 		}
354 		else if (!strcmp(argv[counter], "-t"))
355 		{
356 			counter++;
357 			timer = atoi(argv[counter]);
358 		}
359 		else if (!strcmp(argv[counter], "-v"))
360 		{
361 			counter++;
362 			global_volume = atoi(argv[counter]);
363 		}
364 		else if (!strcmp(argv[counter], "-sn"))
365 		{
366 			show_new_mail = TRUE;
367 		}
368 		else if (!strcmp(argv[counter], "-F"))
369 		{
370 			no_flash = TRUE;
371 		}
372 		else if (!strcmp(argv[counter], "-tally"))
373 		{
374 			show_tally = TRUE;
375 		}
376 		else if (!strncmp(argv[counter], "-geometry", strlen(argv[counter])))
377 		{
378 			counter++;
379 
380 			result = XParseGeometry(argv[counter], &x, &y, &width, &height);
381 			xsh.flags = USPosition | USSize;
382 			x_neg = result & XNegative;
383 			y_neg = result & YNegative;
384 		}
385 		else if (!strncmp(argv[counter], "-summaryGeometry", strlen(argv[counter])))
386 		{
387 			counter++;
388 
389 			result = XParseGeometry(argv[counter], &sx, &sy, &swidth, &sheight);
390 			sxsh.flags = USPosition | USSize;
391 			sx_neg = result & XNegative;
392 			sy_neg = result & YNegative;
393 		}
394 		else if (*argv[counter] == '=')
395 		{
396 			result = XParseGeometry(argv[counter], &x, &y, &width, &height);
397 			xsh.flags = USPosition | USSize;
398 			x_neg = result & XNegative;
399 			y_neg = result & YNegative;
400 		}
401 		else if (!strcmp(argv[counter], "-u"))
402 		{
403 			counter++;
404 			username = argv[counter];
405 		}
406 		else if (!strcmp(argv[counter], "-m"))
407 		{
408 			counter++;
409 			strcpy(mail_file, argv[counter]);
410 		}
411 		else if (!strcmp(argv[counter], "-pop"))
412 		{
413 			new_mail_raise = TRUE;
414 		}
415 		else if (!strcmp(argv[counter], "-beep"))
416 		{
417 			new_mail_beep = TRUE;
418 		}
419 		else if (!strcmp(argv[counter], "-bw"))
420 		{
421 			counter++;
422 			border_width = atoi(argv[counter]);
423 		}
424 		else if (!strcmp(argv[counter], "-ro"))
425 		{
426 			reverse_list = TRUE;
427 		}
428 		else if (!strcmp(argv[counter], "-r"))
429 		{
430 			reverse_video = TRUE;
431 		}
432 		else if (!strcmp(argv[counter], "-R"))
433 		{
434 			new_mail_reverse = TRUE;
435 		}
436 		else if (!strcmp(argv[counter], "-H"))
437 		{
438 			if (!name_set)
439 				hostname_len = FALSE;
440 		}
441 		else if (!strcmp(argv[counter], "-name"))
442 		{
443 			counter++;
444 			name_set = TRUE;
445 			strcpy(hostname, argv[counter]);
446 			hostname_len = strlen(hostname);
447 		}
448 		else if (!strcmp(argv[counter], "-xrm"))
449 		{
450 			/*
451 			 |	ignore
452 			 */
453 			counter++;
454 		}
455 #ifdef DEBUG
456 		else if (!strcmp(argv[counter], "-DEBUG"))
457 		{
458 /*
459  |	The following code will start an hpterm which will in turn execute
460  |	a debugger and "adopt" the process, so it can be debugged.
461  */
462 
463 			int child_id;
464 			char command_line[256];
465 
466 			child_id = getpid();
467 			if (!fork())
468 			{
469 				sprintf(command_line,
470 	      			"hpterm -fg wheat -bg DarkSlateGrey -n %s -e xdb %s -P %d",
471 					"hello",  argv[0], child_id);
472 				execl("/bin/sh", "sh", "-c", command_line, NULL);
473 				fprintf(stderr, "could not exec new window\n");
474 				exit(1);
475 			}
476 
477 /*
478  |	When in debugger, set child_id to zero (p child_id=0) to continue
479  |	executing the software.
480  */
481 
482 			while (child_id != 0)
483 				;
484 		}
485 #endif
486 		else if ((!strcmp(argv[counter], "-?")) || (*argv[counter] == '-'))
487 		{
488 /*
489  |	if option is "-?" or unrecognized, print usage message and exit
490  */
491 
492 			fprintf(stderr, "usage: %s [options]\n", argv[0]);
493 			fprintf(stderr, "          -F (do not flash when new mail)\n");
494 			fprintf(stderr, "          -H (do not display hostname)\n");
495 			fprintf(stderr, "          -R (reverse if new mail)\n");
496 			fprintf(stderr, "          -m mailbox\n");
497 			fprintf(stderr, "          -sn show new mail when received\n");
498 			fprintf(stderr, "          -t time between mailbox checks in seconds\n");
499 			fprintf(stderr, "          -v volume for new mail beep (0-100)\n");
500 			fprintf(stderr, "          -r (reverse video)\n");
501 			fprintf(stderr, "          -u username\n");
502 			fprintf(stderr, "          -fg foreground color\n");
503 			fprintf(stderr, "          -bg background color\n");
504 			fprintf(stderr, "          -bc border color\n");
505 			fprintf(stderr, "          -bw size of border in pixels\n");
506 			fprintf(stderr, "          -fn font name\n");
507 			fprintf(stderr, "          -pop (if new mail, pop to top)\n");
508 			fprintf(stderr, "          -beep (if new mail, notify with sound)\n");
509 			fprintf(stderr, "          -tally (show number of messages, and how many are new)\n");
510 			fprintf(stderr, "          -geometry =geometry\n");
511 			fprintf(stderr, "          -summaryGeometry geometry\n");
512 			fprintf(stderr, "          -display display name\n");
513 			exit(-1);
514 		}
515 	}
516 
517 /*
518  |	if no font was specified, set font to "6x10"
519  */
520 	if (font_name == '\0')
521 		font_name = "fixed";
522 
523 /*
524  |	get the font information
525  */
526 	if ((ae_font = XLoadQueryFont(disp_ptr, font_name)) == 0)
527 	{
528 		fprintf(stderr, "could not open font\n");
529 		exit(1);
530 	}
531 	fontheight = ae_font->ascent + ae_font->descent;
532 	fontwidth = ae_font->max_bounds.rbearing - ae_font->min_bounds.lbearing;
533 /*
534  |	figure out how tall and wide the window should be to display
535  |	the information
536  */
537 	max_lines = (XDisplayHeight(disp_ptr, screen)) / fontheight;
538 	if (lines > max_lines)
539 		lines = max_lines;
540 	max_width = XDisplayWidth(disp_ptr, screen);
541 
542 /*
543  |	set mailbox information if not set by options
544  */
545 
546 	if (mail_file[0] == '\0')
547 	{
548 		strcpy(mail_file, "/var/mail/");
549 		strcat(mail_file, username);
550 	}
551 
552 /*
553  |	make sure mailbox is a file
554  */
555 	temp = stat(mail_file, &buf);
556 	buf.st_mode &= ~07777;
557 	if ((temp != -1) && (buf.st_mode != 0100000) && (buf.st_mode != 0))
558 	{
559 		file_is_dir = TRUE;
560 		new_mail_showing = FALSE;
561 		show_tally = FALSE;
562 	}
563 
564 /*
565  |	set default color information
566  */
567 	background = XWhitePixel(disp_ptr, screen);
568 	foreground = BlackPixel(disp_ptr, screen);
569 	if (reverse_video)
570 	{
571 		border = background;
572 		background = foreground;
573 		foreground = border;
574 	}
575 	border = foreground;
576 	summary_background = background;
577 	summary_foreground = foreground;
578 	new_mail_foreground = foreground;
579 	new_mail_background = background;
580 
581 	win_attrib.background_pixel = background;
582 	win_attrib.border_pixel = foreground;
583 
584 /*
585  |	set up values for placing items in window
586  */
587 
588 	if (hostname_len != FALSE)
589 		width = max(64, max((XTextWidth(ae_font, hostname, strlen(hostname))), width));
590 	else
591 		width = max(64, width);
592 
593 	if (hostname_len != FALSE)
594 		height = max((64+fontheight+2), height);
595 	else
596 		height = max(64, height);
597 
598 	if (show_tally)
599 	{
600 		width = max(width, (XTextWidth(ae_font, "333 msgs", 8)));
601 		width = max(width, (XTextWidth(ae_font, "333 new", 7)));
602 		if (hostname_len)
603 			height = max((64+(3*fontheight)+2), height);
604 		else
605 			height = max((64+(2*fontheight)+2), height);
606 	}
607 
608 /*
609  |	check for negative geometry information
610  */
611 	if (x_neg)
612 		x = XDisplayWidth(disp_ptr, screen) + x - width - (2 * border_width);
613 
614 	if (y_neg)
615 		y = XDisplayHeight(disp_ptr, screen) + y - height - (2 * border_width);
616 
617 /*
618  |	position information for pixmap
619  */
620 	pix_x_offset = (width - 64) / 2;
621 	if ((hostname_len != FALSE) && (!show_tally))
622 		pix_y_offset = (height - (64+fontheight)) / 2;
623 	else if ((hostname_len != FALSE) && (show_tally))
624 		pix_y_offset = (height - (64+(3*fontheight))) / 2;
625 	else if ((hostname_len == FALSE) && (show_tally))
626 		pix_y_offset = (height - (64+(2*fontheight))) / 2;
627 	else
628 		pix_y_offset = (height - 64) / 2;
629 
630 /*
631  |	position information for text
632  */
633 	text_x_offset = (width - (XTextWidth(ae_font, hostname, strlen(hostname)))) / 2;
634 	text_y_offset = pix_y_offset + 64 + ae_font->ascent;
635 
636 #ifdef FORK
637 	if (fork())	/* detach process from tty	*/
638 		exit(0);
639 #endif
640 
641 /*	signal(SIGCLD, SIG_IGN);*/
642 
643 	if ((window_id = XCreateWindow(disp_ptr, RootWindow(disp_ptr, screen),
644 		x, y, width, height, border_width, DefaultDepth(disp_ptr, screen),
645 		InputOutput, DefaultVisual(disp_ptr, screen), (CWBackPixel |
646 		CWBackPixmap | CWColormap), &win_attrib))
647 		== 0)
648 	{
649 		fprintf(stderr, "could not create window\n");
650 		exit(1);
651 	}
652 	if (DisplayPlanes(disp_ptr, screen) > 1) /*check for color ability*/
653 	{
654 		if ((colormap = XDefaultColormap(disp_ptr, screen)) == 0)
655 		{
656 			fprintf(stderr, "XDefaultColormap failed with error %d \n", colormap);
657 			exit(1);
658 		}
659 
660 		if (fg_color != NULL)
661 		{
662 			if (XParseColor(disp_ptr, colormap, fg_color, &exact_def_return) != 0)
663 			{
664 				XAllocColor(disp_ptr, colormap, &exact_def_return);
665 				foreground = exact_def_return.pixel;
666 			}
667 			else
668 			{
669 				fprintf(stderr, "unable to look up color \"%s\" \n", fg_color);
670 				exit(1);
671 			}
672 		}
673 
674 		if (bg_color != NULL)
675 		{
676 			if (XParseColor(disp_ptr, colormap, bg_color, &exact_def_return) != 0)
677 			{
678 				XAllocColor(disp_ptr, colormap, &exact_def_return);
679 				background = exact_def_return.pixel;
680 				XSetWindowBackground(disp_ptr, window_id, background);
681 			}
682 			else
683 			{
684 				fprintf(stderr, "unable to look up color \"%s\" \n", bg_color);
685 				exit(1);
686 			}
687 		}
688 
689 		if (nm_fg_color != NULL)
690 		{
691 			if (XParseColor(disp_ptr, colormap, nm_fg_color, &exact_def_return) != 0)
692 			{
693 				XAllocColor(disp_ptr, colormap, &exact_def_return);
694 				new_mail_foreground = exact_def_return.pixel;
695 			}
696 			else
697 			{
698 				fprintf(stderr, "unable to look up color \"%s\" \n", fg_color);
699 				exit(1);
700 			}
701 		}
702 		else
703 		{
704 			new_mail_foreground = foreground;
705 		}
706 
707 		if (nm_bg_color != NULL)
708 		{
709 			if (XParseColor(disp_ptr, colormap, nm_bg_color, &exact_def_return) != 0)
710 			{
711 				XAllocColor(disp_ptr, colormap, &exact_def_return);
712 				new_mail_background = exact_def_return.pixel;
713 			}
714 			else
715 			{
716 				fprintf(stderr, "unable to look up color \"%s\" \n", bg_color);
717 				exit(1);
718 			}
719 		}
720 		else
721 		{
722 			new_mail_background = background;
723 		}
724 
725 		if (summary_fg_color != NULL)
726 		{
727 			if (XParseColor(disp_ptr, colormap, summary_fg_color, &exact_def_return) != 0)
728 			{
729 				XAllocColor(disp_ptr, colormap, &exact_def_return);
730 				summary_foreground = exact_def_return.pixel;
731 			}
732 			else
733 			{
734 				fprintf(stderr, "unable to look up color \"%s\" \n", fg_color);
735 				exit(1);
736 			}
737 		}
738 		else
739 		{
740 			summary_foreground = foreground;
741 		}
742 
743 		if (summary_bg_color != NULL)
744 		{
745 			if (XParseColor(disp_ptr, colormap, summary_bg_color, &exact_def_return) != 0)
746 			{
747 				XAllocColor(disp_ptr, colormap, &exact_def_return);
748 				summary_background = exact_def_return.pixel;
749 			}
750 			else
751 			{
752 				fprintf(stderr, "unable to look up color \"%s\" \n", bg_color);
753 				exit(1);
754 			}
755 		}
756 		else
757 		{
758 			summary_background = background;
759 		}
760 
761 		if (b_color != NULL)
762 		{
763 			if (XParseColor(disp_ptr, colormap, b_color, &exact_def_return) != 0)
764 			{
765 				XAllocColor(disp_ptr, colormap, &exact_def_return);
766 				border = exact_def_return.pixel;
767 				XSetWindowBorder(disp_ptr, window_id, border);
768 			}
769 			else
770 			{
771 				fprintf(stderr, "unable to look up color \"%s\" \n", bg_color);
772 				exit(1);
773 			}
774 		}
775 	}
776 /*	win_attrib.override_redirect = TRUE;
777 	XChangeWindowAttributes (disp_ptr, window_id, CWOverrideRedirect,
778 		&win_attrib);*/
779 /*
780  |	set up values for graphics context
781  */
782 	gcvalues.font = ae_font->fid;
783 	gcvalues.foreground = foreground;
784 	gcvalues.background = background;
785 	gc = XCreateGC(disp_ptr, window_id, (GCFont | GCForeground |
786 			GCBackground), &gcvalues);
787 	gcvalues.foreground = background;
788 	gcvalues.background = foreground;
789 
790 /*
791  |	set up values for reverse video graphics context
792  */
793 	rev_gc = XCreateGC(disp_ptr, window_id, (GCFont | GCForeground |
794 			GCBackground), &gcvalues);
795 
796 /*
797  |	set up values for new mail graphics context
798  */
799 	gcvalues.foreground = new_mail_foreground;
800 	gcvalues.background = new_mail_background;
801 
802 	new_mail_gc = XCreateGC(disp_ptr, window_id, (GCFont | GCForeground |
803 			GCBackground), &gcvalues);
804 
805 /*
806  |	set up values for summary graphics context
807  */
808 
809 	gcvalues.foreground = summary_foreground;
810 	gcvalues.background = summary_background;
811 
812 	summary_gc = XCreateGC(disp_ptr, window_id, (GCFont | GCForeground |
813 			GCBackground), &gcvalues);
814 
815 /*
816  |	set up bitmaps for the different mailboxes
817  |	(no mail, old mail, or new mail)
818  */
819 	pix[0] = XCreateBitmapFromData(disp_ptr, window_id, nomail_bits, 64, 64);
820 	pix[1] = XCreateBitmapFromData(disp_ptr, window_id, newmail_bits, 64, 64);
821 	pix[2] = XCreateBitmapFromData(disp_ptr, window_id, oldmail_bits, 64, 64);
822 /*
823 	pix[0] = XCreatePixmapFromBitmapData(disp_ptr, window_id, nomail_bits, 64, 64, foreground, background, XDefaultDepth(disp_ptr, screen));
824 	pix[1] = XCreatePixmapFromBitmapData(disp_ptr, window_id, newmail_bits, 64, 64, foreground, background, XDefaultDepth(disp_ptr, screen));
825 	pix[2] = XCreatePixmapFromBitmapData(disp_ptr, window_id, oldmail_bits, 64, 64, foreground, background, XDefaultDepth(disp_ptr, screen));
826 */
827 
828 /*
829  |	set up values for window
830  */
831 	xsh.height = height;
832 	xsh.width  = width;
833 	xsh.x      = x;
834 	xsh.y      = y;
835 	xsh.flags = USPosition | USSize;
836 
837 	XSetStandardProperties(disp_ptr, window_id, "hbiff", "hbiff", pix[1],
838 				argv, argc, &xsh);
839 
840 	XSetCommand(disp_ptr, window_id, argv, argc);
841 
842 	class_spec.res_name = "hbiff";
843 	class_spec.res_class = "HBiff";
844 	XSetClassHint(disp_ptr, window_id, &class_spec);
845 
846 	XSelectInput(disp_ptr, window_id, (ButtonPressMask | KeyPressMask | ExposureMask ));
847 	XMapWindow(disp_ptr, window_id);
848 /*	XNextEvent(disp_ptr, &event);*/
849 	XFlush(disp_ptr);
850 /*	XSetErrorHandler*/
851 	curr_state = 0;
852 
853 /*
854  |	get mailbox status and paint the window
855  */
856 	update_icon(curr_state);
857 	checkmail();
858 	timeout.tv_sec = timer;
859 	timeout.tv_usec = 0;
860 	button_event = (XButtonEvent *) &event;
861 	done = 0;
862 	xfd = ConnectionNumber(disp_ptr);
863 /*
864  |	Loop forever,  examining each event.
865  */
866 	while (!done) {
867 /* Get the next event */
868 		number_of_events = 0;
869 		while (!number_of_events)
870 		{
871 			ttymask = MASK(xfd);
872 			readfds = ttymask;
873 			temp = select(xfd+1, &readfds, 0, 0, &timeout);
874 			number_of_events = XPending(disp_ptr);
875 			if ((temp > 0) && (number_of_events == 0))
876 			{
877 				done++;
878 				break;
879 			}
880 			checkmail();
881 		}
882 		while (XPending(disp_ptr))
883 		{
884 			XNextEvent(disp_ptr, &event);
885 /*
886  |	Determine the event type and deal with it accordingly.
887  */
888 
889 			switch (event.type) {
890 				case Expose:
891 					if (event.xexpose.window == from_wid)
892 						paint_lines(new_mail_showing);
893 					else if (event.xexpose.count == 0)
894 						update_icon(curr_state);
895 					break;
896 				case MappingNotify:
897 					XRefreshKeyboardMapping ( &event);
898 					break;
899 				case KeyPress:
900 					i = XLookupString(&event, text, 10, &key, NULL);
901 					if (i == 1 && text[0] == 'q')
902 						done++;
903 					if (from_wid)
904 						nuke_summary_window();
905 					break;
906 				case ButtonPress:
907 					if ((button_event->button == Button3) && (button_event->state == ShiftMask))
908 						done++;
909 					else if ((button_event->button == Button3) && (child_num == 0))
910 					{
911 						if (from_wid)
912 							nuke_summary_window();
913 						if (no_flash == FALSE)
914 							flash_icon(curr_state);
915 						signal(SIGCHLD, clear_child);
916 						if (!(child_num = fork()))
917 						{
918 							system(mail_command);
919 							exit(0);
920 						}
921 					}
922 					else if ((button_event->button == Button2) && (!from_wid))
923 					{
924 						get_from_lines();
925 						display_lines(FALSE);
926 					}
927 					else if ((button_event->button == Button1) && (curr_state != nomail))
928 					{
929 /*
930  |	reset access time on mailbox, so that hbiff does not think
931  |	there is new mail
932  */
933 						if (from_wid)
934 							nuke_summary_window();
935 						fp = fopen(mail_file, "r");
936 						if (fp != NULL)
937 						{
938 							fgets(buffer, 512, fp);
939 							fclose(fp);
940 						}
941 						checkmail();
942 					}
943 					else if (from_wid)
944 						nuke_summary_window();
945 					unmark_msgs(new_msg_list);
946 					if (curr_state == newmail)
947 					{
948 						curr_state = oldmail;
949 						get_from_lines();
950 						update_icon(curr_state);
951 					}
952 					break;
953 			} /* switch */
954 		}
955 	} /* while (!done) */
956 
957 /*
958  |	leave hbiff
959  */
960 	XFreeGC(disp_ptr, gc);
961 	XFreeGC(disp_ptr, rev_gc);
962 	XFreeGC(disp_ptr, new_mail_gc);
963 	XFreeGC(disp_ptr, summary_gc);
964 	XDestroyWindow(disp_ptr, window_id);
965 	XCloseDisplay(disp_ptr);
966 }
967 
flash_icon(state)968 flash_icon(state)
969 int state;
970 {
971 	paint_window(state, rev_gc, foreground);
972 	sleep(1);
973 	paint_window(state, gc, background);
974 }
975 
paint_window(state,context,background)976 paint_window(state, context, background)
977 int state;
978 GC context;
979 unsigned long background;
980 {
981 	int local_y;
982 	int new_off, msgs_off;
983 
984 	local_y = text_y_offset;
985 	if (show_tally)
986 	{
987 		sprintf(num_of_msgs, "%d msgs", lines);
988 		sprintf(num_of_new, "%d new", new_lines);
989 		new_off = (width - XTextWidth(ae_font, num_of_new, strlen(num_of_new))) / 2;
990 		msgs_off = (width - XTextWidth(ae_font, num_of_msgs, strlen(num_of_msgs))) / 2;
991 	}
992 	XSetWindowBackground(disp_ptr, window_id, background);
993 	XClearWindow(disp_ptr, window_id);
994 	XCopyPlane(disp_ptr, pix[state], window_id, context, 0, 0, width, height, pix_x_offset, pix_y_offset, 1);
995 	if (show_tally)
996 	{
997 		XDrawImageString(disp_ptr, window_id, context, msgs_off, local_y, num_of_msgs, strlen(num_of_msgs));
998 		local_y += fontheight;
999 		if (new_lines)
1000 			XDrawImageString(disp_ptr, window_id, context, new_off, local_y, num_of_new, strlen(num_of_new));
1001 		local_y += fontheight;
1002 	}
1003 	if (hostname_len != FALSE)
1004 		XDrawImageString(disp_ptr, window_id, context, text_x_offset, local_y, hostname, hostname_len);
1005 	XFlush(disp_ptr);
1006 }
1007 
update_icon(state)1008 update_icon(state)
1009 int state;
1010 {
1011 	if ((state == newmail) && (!new_mail_reverse))
1012 	{
1013 		paint_window(state, new_mail_gc, new_mail_background);
1014 	}
1015 	else if (reverse_on)
1016 	{
1017 		paint_window(state, rev_gc, foreground);
1018 	}
1019 	else
1020 	{
1021 		paint_window(state, gc, background);
1022 	}
1023 	XSetStandardProperties(disp_ptr, window_id, "hbiff", "hbiff",
1024 				pix[state], argv1, argc1, &xsh);
1025 
1026 	XFlush(disp_ptr);
1027 }
1028 
checkmail()1029 checkmail()
1030 {
1031 	static int old_state = 0;	/* initially "nomail"	*/
1032 	static int file_size = 0;
1033 	static struct stat file_status;
1034 	static time_t last_modified = 0;
1035 	static struct utimbuf timebuf;
1036 
1037 	old_state = curr_state;
1038 	if (stat(mail_file, &file_status) == -1)
1039 	{
1040 		curr_state = nomail;
1041 		file_status.st_size = 0;
1042 	}
1043 	else
1044 	{
1045 		if (file_status.st_size == 0)
1046 			curr_state = nomail;
1047 		else if ((file_status.st_atime <= file_status.st_mtime) ||
1048 			 ((file_status.st_atime <= last_hbiff_access) &&
1049 			  (curr_state == newmail)))
1050 		{
1051 			curr_state = newmail;
1052 /*
1053  |	Even if the window already indicates new mail, do the appropriate
1054  |	operations if there is more new mail.
1055  */
1056 			if ((old_state == curr_state) && (last_modified < file_status.st_mtime))
1057 			{
1058 				old_state = oldmail;
1059 			}
1060 			last_modified = file_status.st_mtime;
1061 		}
1062 		else /* if (file_status.st_atime > file_status.st_mtime) */
1063 		{
1064 			curr_state = oldmail;
1065 			if (((file_status.st_ctime > last_hbiff_access) ||
1066 			     (file_status.st_atime > last_hbiff_access)) &&
1067 			    (show_new_mail || show_tally))
1068 			{
1069 				get_from_lines();
1070 				update_icon(curr_state);
1071 			}
1072 		}
1073 	}
1074 	if (curr_state != newmail)
1075 		reverse_on = FALSE;
1076 	if (old_state != curr_state)
1077 	{
1078 		if (from_wid)
1079 			nuke_summary_window();
1080 		get_from_lines();
1081 		if (curr_state == newmail)
1082 		{
1083 			if (!file_is_dir)
1084 			{
1085 			/*
1086 			 |	Reset file times so that other mechanisms will
1087 			 |	still be able to detect that mail is new.
1088 			 */
1089 				timebuf.actime = timebuf.modtime = last_modified;
1090 				utime(mail_file, &timebuf);
1091 			}
1092 
1093 			if (new_mail_reverse)
1094 				reverse_on = TRUE;
1095 			if (new_mail_raise)
1096 			{
1097 				XRaiseWindow(disp_ptr, window_id);
1098 				XFlush(disp_ptr);
1099 				update_icon(curr_state);
1100 			}
1101 			if (no_flash == FALSE)
1102 			{
1103 				flash_icon(curr_state);
1104 				sleep(1);
1105 				flash_icon(curr_state);
1106 			}
1107 			if (new_mail_beep)
1108 				beep_new();
1109 			if (show_new_mail && new_lines)
1110 			{
1111 				new_mail_showing = TRUE;
1112 				display_lines(new_mail_showing);
1113 			}
1114 		}
1115 		else
1116 			unmark_msgs(new_msg_list);
1117 		update_icon(curr_state);
1118 	}
1119 }
1120 
get_defaults()1121 get_defaults()
1122 {
1123 	char *string;
1124 
1125 	summary_fg_color = XGetDefault(disp_ptr, "hbiff", "summaryForeground");
1126 	summary_bg_color = XGetDefault(disp_ptr, "hbiff", "summaryBackground");
1127 	nm_fg_color = XGetDefault(disp_ptr, "hbiff", "newMailForeground");
1128 	nm_bg_color = XGetDefault(disp_ptr, "hbiff", "newMailBackground");
1129 	fg_color = XGetDefault(disp_ptr, "hbiff", "foreground");
1130 	bg_color = XGetDefault(disp_ptr, "hbiff", "background");
1131 	b_color = XGetDefault(disp_ptr, "hbiff", "borderColor");
1132 	if (string = XGetDefault(disp_ptr, "hbiff", "time"))
1133 		timer = atoi(string);
1134 	if (string = XGetDefault(disp_ptr, "hbiff", "volume"))
1135 		global_volume = atoi(string);
1136 
1137 	if (string = XGetDefault(disp_ptr, "hbiff", "geometry"))
1138 	{
1139 		result = XParseGeometry(string, &x, &y, &width, &height);
1140 		xsh.flags = USPosition | USSize;
1141 		x_neg = result & XNegative;
1142 		y_neg = result & YNegative;
1143 	}
1144 	if (string = XGetDefault(disp_ptr, "hbiff", "summaryGeometry"))
1145 	{
1146 		result = XParseGeometry(string, &sx, &sy, &swidth, &sheight);
1147 		sxsh.flags = USPosition | USSize;
1148 		sx_neg = result & XNegative;
1149 		sy_neg = result & YNegative;
1150 	}
1151 	if (string = XGetDefault(disp_ptr, "hbiff", "newMailRaise"))
1152 	{
1153 		new_mail_raise = yes_string(string);
1154 	}
1155 	if (string = XGetDefault(disp_ptr, "hbiff", "newMailBeep"))
1156 	{
1157 		new_mail_beep = yes_string(string);
1158 	}
1159 	if (string = XGetDefault(disp_ptr, "hbiff", "borderWidth"))
1160 		border_width = atoi(string);
1161 	if (string = XGetDefault(disp_ptr, "hbiff", "mailCommand"))
1162 	{
1163 		mail_command = (char *) malloc(strlen(string) + 1);
1164 		strcpy(mail_command, string);
1165 	}
1166 	if (string = XGetDefault(disp_ptr, "hbiff", "fontName"))
1167 		font_name = string;
1168 	if (string = XGetDefault(disp_ptr, "hbiff", "reverseVideo"))
1169 	{
1170 		reverse_video = yes_string(string);
1171 	}
1172 	if (string = XGetDefault(disp_ptr, "hbiff", "reverseOrder"))
1173 	{
1174 		reverse_list = yes_string(string);
1175 	}
1176 	if (string = XGetDefault(disp_ptr, "hbiff", "newMailReverse"))
1177 	{
1178 		new_mail_reverse = yes_string(string);
1179 	}
1180 	if (string = XGetDefault(disp_ptr, "hbiff", "showNewMail"))
1181 	{
1182 		show_new_mail = yes_string(string);
1183 	}
1184 	if (string = XGetDefault(disp_ptr, "hbiff", "tally"))
1185 	{
1186 		show_tally = yes_string(string);
1187 	}
1188 	if (string = XGetDefault(disp_ptr, "hbiff", "noFlash"))
1189 	{
1190 		no_flash = yes_string(string);
1191 	}
1192 	if (string = XGetDefault(disp_ptr, "hbiff", "noHostname"))
1193 	{
1194 		if ((yes_string(string)) && (!name_set))
1195 			hostname_len = FALSE;
1196 	}
1197 	if (string = XGetDefault(disp_ptr, "hbiff", "name"))
1198 	{
1199 		strcpy(hostname, string);
1200 		name_set = TRUE;
1201 		hostname_len = strlen(hostname);
1202 	}
1203 }
1204 
1205 /*
1206  |	check string for a positive value (on, yes, true)
1207  */
1208 
yes_string(string)1209 yes_string(string)
1210 char *string;
1211 {
1212 	char temp_string[16];
1213 	int counter;
1214 
1215 	if (strlen(string) > 4)
1216 		return(FALSE);
1217 
1218 	for (counter = 0; counter < strlen(string); counter++)
1219 		temp_string[counter] = toupper(string[counter]);
1220 
1221 	temp_string[counter] = NULL;
1222 
1223 	if ((strcmp(temp_string, "YES") == 0)
1224 		|| (strcmp(temp_string, "TRUE") == 0)
1225 			|| (strcmp(temp_string, "ON") == 0))
1226 		return(TRUE);
1227 	else
1228 		return(FALSE);
1229 }
1230 
1231 /*
1232  |	Create list of mail messages, and check for messages that were not
1233  |	present previously.  For messages that were considered new in the
1234  |	old list, set flag to indicate that they are new in the new list, too.
1235  */
1236 
get_from_lines()1237 get_from_lines()
1238 {
1239 	int counter;
1240 	char *file_name;
1241 	struct from_text *list_head, *temp_ptr;
1242 	struct from_text *new_ptr, *old_ptr;
1243 	char buffer[512];
1244 	char buffer2[512];
1245 	char from_buffer[512];
1246 	char subj_buffer[512];
1247 	char *temp;
1248 	int sub_flag;
1249 	int from_flag;
1250 	int line_len, max_len;
1251 	int max_lines, max_width;
1252 	int done;
1253 	int temp_int;
1254 	int found;
1255 	struct stat file_status;
1256 
1257 	if (file_is_dir)
1258 		return(0);
1259 
1260 	lines = 0;
1261 	new_lines = 0;
1262 
1263 	if (old_msg_list != NULL)
1264 	{
1265 		free_list(old_msg_list);
1266 	}
1267 	old_msg_list = new_msg_list;
1268 	new_msg_list = NULL;
1269 
1270 	temp_int = stat(mail_file, &file_status);
1271 
1272 	if (temp_int != -1)
1273 	{
1274 		last_hbiff_access = file_status.st_atime;
1275 		/*
1276 		 |	make sure that file is non-zero size
1277 		 */
1278 		if (file_status.st_size == 0)
1279 			return(0);
1280 	}
1281 	else
1282 	{
1283 		/*
1284 		 |	couldn't stat the file
1285 		 */
1286 		return(0);
1287 	}
1288 
1289 
1290 /*
1291  |	open mailbox
1292  */
1293 	if ((fp = fopen(mail_file, "r")) == NULL)
1294 		return(0);
1295 
1296 	sub_flag = from_flag = FALSE;
1297 	memset(buffer2, 0, 512);
1298 	memset(subj_buffer, 0, 512);
1299 	memset(from_buffer, 0, 512);
1300 	list_head = NULL;
1301 
1302 /*
1303  |	create a linked list of lines containing the "From" and "Subject:"
1304  |	information from each mail message
1305  */
1306 	while ((temp = fgets(buffer, 512, fp)) != NULL)
1307 	{
1308 		if (!(strncmp(buffer, "From ", 5)))	/* start of message */
1309 		{
1310 			from_flag = TRUE;
1311 			strncpy(from_buffer, buffer, (strlen(buffer) - 1));
1312 		}
1313 		else if ((!(strncmp(buffer, "From: ", 5))) && from_flag)
1314 		{
1315 			from_parse(from_buffer, buffer);
1316 		}
1317 		else if ((!(strncmp(buffer, "Subject: ", 6))) && from_flag &&
1318 			 (subj_buffer[0] == NULL))
1319 		{
1320 			sub_flag = TRUE;
1321 			strncat(subj_buffer, " [", 2);
1322 			strncat(subj_buffer, buffer, (strlen(buffer) - 1));
1323 			strncat(subj_buffer, "]", 1);
1324 		}
1325 		else if (((buffer[0] == '\n') || (buffer[0] == '\r')) && (from_flag))
1326 		{
1327 			strcpy(buffer2, from_buffer);
1328 			strcat(buffer2, subj_buffer);
1329 			memset(from_buffer, 0, 512);
1330 			memset(subj_buffer, 0, 512);
1331 			if (list_head == NULL)
1332 				temp_ptr = list_head = (struct from_text *) malloc(sizeof(struct from_text));
1333 			else
1334 			{
1335 				temp_ptr = list_head;
1336 				while (temp_ptr->next != NULL)
1337 					temp_ptr = temp_ptr->next;
1338 				temp_ptr->next = (struct from_text *) malloc(sizeof(struct from_text));
1339 				temp_ptr = temp_ptr->next;
1340 			}
1341 			temp_ptr->flag = FALSE;
1342 			temp_ptr->length = strlen(buffer2) + 2;
1343 			temp_ptr->string = (char *) malloc(temp_ptr->length);
1344 			strcpy(temp_ptr->string, " ");
1345 			strcat(temp_ptr->string, buffer2);
1346 			temp_ptr->next = NULL;
1347 			from_flag = sub_flag = FALSE;
1348 			lines++;
1349 			memset(buffer2, 0, 512);
1350 		}
1351 	}
1352 
1353 	if (list_head == 0)
1354 	{
1355 		/*
1356 		 |	The mailbox is not in an expected format!
1357 		 */
1358 		fprintf(stderr, "hbiff: mailbox corrupted!\n");
1359 		fclose(fp);
1360 		return(0);
1361 	}
1362 
1363 	temp_ptr = list_head;
1364 
1365 	/*
1366 	 |	indicate which is the most recent message
1367 	 */
1368 
1369 	while (temp_ptr->next != NULL)
1370 		temp_ptr = temp_ptr->next;
1371 	temp_ptr->string[0] = '>';
1372 	temp_ptr = list_head;
1373 
1374 	if (reverse_list)
1375 	{
1376 		while (list_head->next != NULL)
1377 			list_head = list_head->next;
1378 		reverse_order(temp_ptr);
1379 		temp_ptr = list_head;
1380 	}
1381 
1382 	new_msg_list = list_head;
1383 
1384 	for (new_ptr = new_msg_list; new_ptr != NULL; new_ptr = new_ptr->next)
1385 	{
1386 		found = FALSE;
1387 		for (old_ptr = old_msg_list; (old_ptr != NULL) && (!found);
1388 			old_ptr = old_ptr->next)
1389 		{
1390 			if (old_ptr->string && (!strcmp((new_ptr->string+1), (old_ptr->string+1))))
1391 			{
1392 				free(old_ptr->string);
1393 				old_ptr->string = NULL;
1394 				found = TRUE;
1395 				if (old_ptr->flag)
1396 				{
1397 					new_lines++;
1398 					new_ptr->flag = TRUE;
1399 				}
1400 			}
1401 		}
1402 		if ((!found) && (curr_state == newmail))
1403 		{
1404 			new_lines++;
1405 			new_ptr->flag = TRUE;
1406 		}
1407 	}
1408 	fclose(fp);
1409 	if (stat(mail_file, &file_status) != -1)
1410 	{
1411 		last_hbiff_access = file_status.st_atime;
1412 	}
1413 }
1414 
1415 /*
1416  |	Create window of appropriate size to display mail summary.
1417  */
1418 
display_lines(new_mail_only)1419 display_lines(new_mail_only)
1420 int new_mail_only;
1421 {
1422 	XSizeHints xsh;
1423 	char *file_name;
1424 	char buffer[512];
1425 	char buffer2[512];
1426 	char from_buffer[512];
1427 	char subj_buffer[512];
1428 	char *temp;
1429 	int sub_flag;
1430 	int from_flag;
1431 	int line_len = 0, max_len = 0;
1432 	int done;
1433 	int temp_int;
1434 	int counter;
1435 	int lines_to_display = 0;
1436 	struct from_text *temp_ptr;
1437 
1438 	/* copy size hints */
1439 	xsh.flags = sxsh.flags;
1440 	xsh.x = sx;
1441 	xsh.y = sy;
1442 	xsh.width = sxsh.width;
1443 	xsh.height = sxsh.height;
1444 
1445 	temp_ptr = new_msg_list;
1446 
1447 	while (temp_ptr != NULL)
1448 	{
1449 		if ((new_mail_only && temp_ptr->flag) || (!new_mail_only))
1450 		{
1451 			lines_to_display++;
1452 			line_len = XTextWidth(ae_font, temp_ptr->string, (temp_ptr->length -1));
1453 		}
1454 		if (line_len > max_len)
1455 			max_len = line_len;
1456 		temp_ptr = temp_ptr->next;
1457 	}
1458 
1459 	if (lines_to_display == 0)
1460 		return(0);
1461 
1462 	if (max_len > max_width)
1463 		max_len = max_width;
1464 
1465 /*
1466  |	set up summary window information
1467  */
1468 
1469 	xsh.height = lines_to_display * fontheight;
1470 	xsh.width  = max_len + 6;
1471 
1472 	if (sxsh.flags == (USPosition | USSize)) /* really specified by user */
1473 	{
1474 	/*
1475 	 |	check for negative geometry information
1476 	 */
1477 		if (sx_neg)
1478 			xsh.x = XDisplayWidth(disp_ptr, screen) + sx - xsh.width - (2 * border_width);
1479 		else
1480 			xsh.x = sx;
1481 		if (sy_neg)
1482 			xsh.y = XDisplayHeight(disp_ptr, screen) + sy - xsh.height - (2 * border_width);
1483 		else
1484 			xsh.y = sy;
1485 	}
1486 	else
1487 	{
1488 		xsh.x      = max(0, (x - xsh.width));
1489 		xsh.y      = max(0, (y - xsh.height));
1490 		xsh.flags = USPosition | USSize;
1491 	}
1492 
1493 	if ((from_wid = XCreateWindow(disp_ptr, RootWindow(disp_ptr, screen),
1494 		xsh.x, xsh.y, xsh.width, xsh.height, border_width,
1495 		DefaultDepth(disp_ptr, screen),
1496 		InputOutput, DefaultVisual(disp_ptr, screen), (CWBackPixel |
1497 		CWBackPixmap | CWColormap), &win_attrib))
1498 		== 0)
1499 	{
1500 		fprintf(stderr, "could not create window for \"From\" info\n");
1501 	}
1502 
1503 	XSetStandardProperties(disp_ptr, from_wid, "hbiff", "hbiff", pix[1],
1504 				argv1, argc1, &xsh);
1505 
1506 	XSetClassHint(disp_ptr, from_wid, &class_spec);
1507 	XSetWindowBackground(disp_ptr, from_wid, summary_background);
1508 	XSelectInput(disp_ptr, from_wid, (ButtonPressMask | KeyPressMask | ExposureMask ));
1509 	XMapWindow(disp_ptr, from_wid);
1510 	XFlush(disp_ptr);
1511 
1512 	paint_lines(new_mail_only);
1513 }
1514 
1515 /*
1516  |	Print appropriate summary information in summary window.
1517  */
1518 
paint_lines(new_mail_only)1519 paint_lines(new_mail_only)
1520 int new_mail_only;
1521 {
1522 	struct from_text *temp_ptr;
1523 	int counter, i;
1524 /*
1525  |	display the text
1526  */
1527 	for (i = 0, temp_ptr = new_msg_list, counter = 0; i < lines; i++)
1528 	{
1529 		if ((new_mail_only & temp_ptr->flag) || (!new_mail_only))
1530 		{
1531 			XDrawImageString(disp_ptr, from_wid, summary_gc, 2,
1532 			  ((counter * fontheight) + ae_font->ascent),
1533 			  temp_ptr->string, (temp_ptr->length - 1));
1534 			counter++;
1535 		}
1536 		temp_ptr = temp_ptr->next;
1537 	}
1538 	XFlush(disp_ptr);
1539 }
1540 
nuke_summary_window()1541 nuke_summary_window()
1542 {
1543 /*
1544  |	Destroy summary window.
1545  */
1546 
1547 	XDestroyWindow(disp_ptr, from_wid);
1548 	from_wid = 0;
1549 	new_mail_showing = FALSE;
1550 }
1551 
1552 /*
1553  |	Recursively traverse the list and reverse the ordering.
1554  */
1555 
1556 reverse_order(ptr)
1557 struct from_text *ptr;
1558 {
1559 	struct from_text *tmp_ptr;
1560 
1561 	if (ptr->next != NULL)
1562 	{
1563 		reverse_order(ptr->next);
1564 		ptr->next->next = ptr;
1565 		ptr->next = NULL;
1566 	}
1567 }
1568 
1569 /*
1570  |	Traverse the list and reset flags indicating that a message is
1571  |	considered new.
1572  */
1573 
1574 unmark_msgs(ptr)
1575 struct from_text *ptr;
1576 {
1577 	struct from_text *tmp_ptr = ptr;
1578 
1579 	while (tmp_ptr != NULL)
1580 	{
1581 		tmp_ptr->flag = FALSE;
1582 		tmp_ptr = tmp_ptr->next;
1583 	}
1584 	new_lines = 0;
1585 }
1586 
1587 free_list(ptr)
1588 struct from_text *ptr;
1589 {
1590 /*
1591  |	recursively traverse linked list, freeing data
1592  */
1593 	if (ptr->next != NULL)
1594 	{
1595 		free_list(ptr->next);
1596 	}
1597 	if (ptr->string != NULL)
1598 	{
1599 		free(ptr->string);
1600 	}
1601 	free(ptr);
1602 }
1603 
from_parse(out_buffer,in_buffer)1604 from_parse(out_buffer, in_buffer)
1605 char *out_buffer, *in_buffer;
1606 {
1607 	int counter;
1608 	char *temp_ptr;
1609 	char *start_of_name;
1610 	char open_paren, close_paren;
1611 
1612 	open_paren = '(';
1613 	close_paren = ')';
1614 
1615 	memset(out_buffer, 0, 512);
1616 
1617 	if ((temp_ptr = strchr(in_buffer, '"')))
1618 	{
1619 		/* move to first character after open quote */
1620 		temp_ptr++;
1621 		start_of_name = temp_ptr;
1622 		for (counter = 0; ((*temp_ptr != NULL) &&
1623 		     (*temp_ptr != '"') && (counter < 512)); counter++)
1624 			temp_ptr++;
1625 		strcpy(out_buffer, "From: ");
1626 		strncat(out_buffer, start_of_name, counter);
1627 	}
1628 	else if ((temp_ptr = strchr(in_buffer, open_paren)))
1629 	{
1630 		/* move to first character after open paren */
1631 		temp_ptr++;
1632 		start_of_name = temp_ptr;
1633 		for (counter = 0; ((*temp_ptr != NULL) &&
1634 		     (*temp_ptr != close_paren) && (counter < 512)); counter++)
1635 			temp_ptr++;
1636 		strcpy(out_buffer, "From: ");
1637 		strncat(out_buffer, start_of_name, counter);
1638 	}
1639 	else if ((temp_ptr = strchr(in_buffer, '<')))
1640 	{
1641 		temp_ptr = in_buffer;
1642 		while ((*temp_ptr != ' ') && (*temp_ptr != NULL))
1643 			temp_ptr++;
1644 		while ((*temp_ptr == ' ') && (*temp_ptr != NULL))
1645 			temp_ptr++;
1646 		start_of_name = temp_ptr;
1647 		for (counter = 0; ((*temp_ptr != NULL) &&
1648 		     (*temp_ptr != '<') && (counter < 512)); counter++)
1649 			temp_ptr++;
1650 		strcpy(out_buffer, "From: ");
1651 		strncat(out_buffer, start_of_name, counter);
1652 	}
1653 	else
1654 	{
1655 		strncpy(out_buffer, in_buffer, (strlen(in_buffer) - 1));
1656 	}
1657 }
1658 
clear_child()1659 clear_child()
1660 {
1661 	int value;
1662 
1663 	value = wait(0);
1664 	if (value == child_num)
1665 		child_num = 0;
1666 }
1667 
1668 /*
1669  |	The code for setting the beeper to a different tone, beeping, and
1670  |	restoring the beeper settings to what they were before is taken from
1671  |	code written by Roger Petersen.
1672  */
1673 
restore_kbd()1674 restore_kbd()
1675 {
1676     int mask;
1677     /* Restore initial bell values */
1678     mask = KBBellPercent | KBBellPitch | KBBellDuration;
1679     XChangeKeyboardControl(disp_ptr, mask, &save_kbd);
1680 
1681     XFlush (disp_ptr);
1682 }
1683 
high_res_sleep(milli_seconds)1684 void high_res_sleep(milli_seconds)
1685 long milli_seconds;
1686 {
1687     int             fds = 0;
1688     struct timeval  timeout;
1689 
1690     timeout.tv_sec  = milli_seconds / 1000; 		/* Seconds */
1691     timeout.tv_usec = (milli_seconds % 1000) * 1000; 	/* Micro-seconds */
1692     select(0, &fds, &fds, &fds, &timeout);
1693 }
1694 
1695 #define SLEEP_TIMER_OVERHEAD 20;   /* Milliseconds overhead in sleep routine */
1696 
1697 /*
1698  * Play a tone.
1699  * The HP buffer-box with speaker seems to be capable of a range from
1700  * 82 Hz thru 16666 Hz inclusive.
1701  * 0 to 81 Hz are non-existent.  16667 Hz and above are non-existent.
1702  */
tone(volume,pitch,duration)1703 void tone(volume, pitch, duration)
1704 int volume, pitch, duration;
1705 {
1706     XKeyboardControl	set_bell;
1707     unsigned int 	mask;
1708     unsigned int 	overhead;
1709 
1710     overhead = SLEEP_TIMER_OVERHEAD;	/* May need to be fancier, someday. */
1711     if (duration < (overhead + 10)) overhead = 0;
1712 
1713     /* Limit changes to Bell */
1714     mask = KBBellPercent | KBBellPitch | KBBellDuration;
1715 
1716     /* Make some changes. */
1717     set_bell.bell_percent = volume;
1718     set_bell.bell_pitch  = pitch;
1719     set_bell.bell_duration = duration;
1720     XChangeKeyboardControl(disp_ptr, mask, &set_bell);
1721     XBell (disp_ptr, 0);
1722     XFlush (disp_ptr);
1723     high_res_sleep(duration - overhead);
1724 }
1725 
beep_new()1726 beep_new()
1727 {
1728     XKeyboardState	query_kbd;
1729 
1730     /* Save current values in query_kbd */
1731     XGetKeyboardControl(disp_ptr, &query_kbd);
1732 
1733     save_kbd.bell_percent = query_kbd.bell_percent;
1734     save_kbd.bell_pitch  = query_kbd.bell_pitch;
1735     save_kbd.bell_duration = query_kbd.bell_duration;
1736 
1737     tone(global_volume, 523, 360);
1738     tone(global_volume, 1, 40);
1739     tone(global_volume, 392, 720);
1740 
1741     restore_kbd();
1742 }
1743