Browse Source

more work on the error report window

Enrico Tassi 12 years ago
parent
commit
7106112574
2 changed files with 222 additions and 45 deletions
  1. 14
    1
      smd-applet.ui
  2. 208
    44
      smd-applet.vala

+ 14
- 1
smd-applet.ui View File

@@ -301,6 +301,7 @@
301 301
                                 <property name="vscrollbar_policy">automatic</property>
302 302
                                 <child>
303 303
                                   <object class="GtkTextView" id="tvMail">
304
+                                    <property name="height_request">200</property>
304 305
                                     <property name="visible">True</property>
305 306
                                     <property name="can_focus">True</property>
306 307
                                     <property name="editable">False</property>
@@ -362,7 +363,19 @@
362 363
                             <property name="visible">True</property>
363 364
                             <property name="left_padding">12</property>
364 365
                             <child>
365
-                              <placeholder/>
366
+                              <object class="GtkVBox" id="vbRun">
367
+                                <property name="visible">True</property>
368
+                                <property name="orientation">vertical</property>
369
+                                <child>
370
+                                  <placeholder/>
371
+                                </child>
372
+                                <child>
373
+                                  <placeholder/>
374
+                                </child>
375
+                                <child>
376
+                                  <placeholder/>
377
+                                </child>
378
+                              </object>
366 379
                             </child>
367 380
                           </object>
368 381
                         </child>

+ 208
- 44
smd-applet.vala View File

@@ -2,15 +2,34 @@
2 2
 // No warranties.
3 3
 // Copyright 2009 Enrico Tassi <gares@fettunta.org>
4 4
 
5
-// TODO : use glib checksum functions instead of gcrypt
6
-
7 5
 // a simple class to pass data from the child process to the
8 6
 // notofier
9 7
 class Event {
10 8
 	public string message;
9
+	public bool enter_error_mode;
10
+
11
+	public static Event error(string account, string host) {
12
+		var e = new Event();
13
+		e.message = "An error occurred";
14
+		e.enter_error_mode = true;
15
+		return e;
16
+	}
11 17
 
12
-	Event(string s) {
13
-		message = s;
18
+	public static Event stats(
19
+		string account,string host,int new_mails,int del_mails) 
20
+	{
21
+		string preamble = "Synchronize with %s:\n".printf(account);
22
+		var e = new Event();
23
+		e.enter_error_mode = false;
24
+		if (new_mails > 0 && del_mails > 0) {
25
+			e.message = "%s%d new messages\n%d deleted messages".
26
+				printf(preamble,new_mails,del_mails);
27
+		} else if (new_mails > 0) {
28
+			e.message = "%s%d new messages".printf(preamble,new_mails);
29
+		} else {
30
+			e.message = "%s%d deleted messages".printf(preamble,del_mails);
31
+		}
32
+		return e;
14 33
 	}
15 34
 }
16 35
 
@@ -33,10 +52,14 @@ class smdApplet {
33 52
 
34 53
 	// =================== the data =====================================
35 54
 
55
+	// The builder
56
+	Gtk.Builder builder = null;
57
+
36 58
 	// main widgets
37 59
 	Gtk.Menu menu = null;
38 60
 	Gtk.StatusIcon si = null;
39 61
 	Gtk.Window win = null;
62
+	Gtk.Window err_win = null;
40 63
 
41 64
 	// the gconf client handler
42 65
 	GConf.Client gconf = null;
@@ -49,12 +72,16 @@ class smdApplet {
49 72
 	GLib.Mutex events_lock = null;
50 73
 	List<Event> events = null; 
51 74
 
75
+	// if the program is stuck
76
+	bool error_mode;
77
+	GLib.HashTable<Gtk.Widget,string> command_hash = null;
78
+
52 79
 	// =================== the code =====================================
53 80
 
54 81
 	// initialize data structures and build gtk+ widgets
55 82
 	smdApplet() {
56 83
 		// load the ui file
57
-		Gtk.Builder builder = new Gtk.Builder ();
84
+		builder = new Gtk.Builder ();
58 85
 		try { builder.add_from_file (smd_applet_ui); } 
59 86
 		catch (GLib.Error e) { 
60 87
 			stderr.printf("%s\n",e.message); 
@@ -70,6 +97,7 @@ class smdApplet {
70 97
 
71 98
 		// load widgets and attach callbacks
72 99
 		win = builder.get_object("wPrefs") as Gtk.Window;
100
+		err_win = builder.get_object("wError") as Gtk.Window;
73 101
 		var close = builder.get_object("bClose") as Gtk.Button;
74 102
 		close.clicked += (b) =>  { win.hide(); };
75 103
 		var bicon = builder.get_object("cbIcon") as Gtk.CheckButton;
@@ -95,12 +123,19 @@ class smdApplet {
95 123
 		prefs.activate += (b) => {  win.show(); };
96 124
 
97 125
 		// notification area icon (XXX draw a decent one)
98
-		si = new Gtk.StatusIcon.from_stock(Gtk.STOCK_NETWORK);
126
+		si = new Gtk.StatusIcon.from_stock(Gtk.STOCK_INFO);
99 127
 		si.activate += (s) => { 
100
-			menu.popup(null,null,si.position_menu,0,
101
-				Gtk.get_current_event_time());
128
+			if ( error_mode ) 
129
+				err_win.show();
130
+			else
131
+				menu.popup(null,null,si.position_menu,0,
132
+					Gtk.get_current_event_time());
102 133
 		};
103 134
 		si.set_visible(true);
135
+
136
+		// error mode
137
+		command_hash = new GLib.HashTable<Gtk.Widget,string>(
138
+			GLib.direct_hash,GLib.str_equal);
104 139
 	}
105 140
 
106 141
 	// This thread fills the event queue, parsing the
@@ -117,60 +152,177 @@ class smdApplet {
117 152
 	public bool eval_smd_loop_message(string s){
118 153
 		try {
119 154
 			GLib.MatchInfo info = null;
120
-			var stats = new GLib.Regex(
121
-				"^([^:]+): smd-(client|server)@([^:]+): TAGS: stats::(.*)$");
122
-			var error = new GLib.Regex(
123
-				"^([^:]+): smd-(client|server)@([^:]+): TAGS: error::(.*)$");
124
-			var skip = new GLib.Regex("^ERROR:");
125
-			if (stats.match(s,0,out info)) {
126
-				var neW = new GLib.Regex("new-mails\\(([0-9]+)\\)");
127
-				var del = new GLib.Regex("del-mails\\(([0-9]+)\\)");
155
+			var r_tags = new GLib.Regex(
156
+				"^([^:]+): smd-(client|server)@([^:]+): TAGS:(.*)$");
157
+			var r_skip = new GLib.Regex(
158
+				"^([^:]+): smd-(client|server)@([^:]+): ERROR");
159
+
160
+			if (r_skip.match(s,0,null)) { return false; }
161
+			if (!r_tags.match(s,0,out info)) {
162
+				stderr.printf("unhandled smd-loop message: %s\n",s);
163
+				return true;
164
+			}
165
+			
166
+			var account = info.fetch(1);
167
+			var host = info.fetch(3);
168
+			var tags = info.fetch(4);
169
+			
170
+			GLib.MatchInfo i_args = null;
171
+			var r_stats = new GLib.Regex(" stats::(.*)$");
172
+			var r_error = new GLib.Regex(" error::(.*)$");
173
+
174
+			if (r_stats.match(tags,0,out i_args)) {
175
+				var r_neW = new GLib.Regex("new-mails\\(([0-9]+)\\)");
176
+				var r_del = new GLib.Regex("del-mails\\(([0-9]+)\\)");
128 177
 				GLib.MatchInfo i_new = null, i_del = null;
178
+				var args = i_args.fetch(1);
129 179
 
130 180
 				// check if matches
131
-				neW.match(info.fetch(4),0,out i_new);
132
-				del.match(info.fetch(4),0,out i_del);
133
-
134
-				int new_mails = i_new.fetch(1).to_int();	
135
-				int del_mails = i_del.fetch(1).to_int();	
136
-
137
-				string message = null;
138
-				if (del_mails > 0) {
139
-					message = " %d new mails\n %d mails were deleted".
140
-						printf(new_mails,del_mails);
181
+				var has_new = r_neW.match(args,0,out i_new); 
182
+				var has_del = r_del.match(args,0,out i_del);
183
+
184
+				int new_mails = 0;
185
+				if (has_new) { new_mails = i_new.fetch(1).to_int();	}
186
+				int del_mails = 0;
187
+				if (has_del) { del_mails = i_del.fetch(1).to_int();	}
188
+
189
+				if (host == "localhost" && (new_mails > 0 || del_mails > 0)) {
190
+					events_lock.lock();
191
+					events.append(
192
+						Event.stats(account,host,new_mails, del_mails));
193
+					events_lock.unlock();
141 194
 				} else {
142
-					message = " %d new mails".
143
-						printf(new_mails);
195
+					// we skip non-error messages from the remote host
144 196
 				}
145
-				events_lock.lock();
146
-				events.append(new Event(
147
-					"Mail synchronization with <i>%s</i>:\n%s".
148
-					printf(info.fetch(1),message)));
149
-				events_lock.unlock();
197
+
150 198
 				return false;
151
-			} else if (error.match(s,0,out info)) {
199
+			} else if (r_error.match(tags,0,out i_args)) {
152 200
 				var context = new GLib.Regex("context\\(([^\\)]+)\\)");
153 201
 				var cause = new GLib.Regex("probable-cause\\(([^\\)]+)\\)");
154 202
 				var human = new GLib.Regex("human-intervention\\(([^\\)]+)\\)");
155
-				//var actions = new GLib.Regex("suggested-action\\(([^\\)]+)\\)");
203
+				var actions=new GLib.Regex("suggested-action\\((.*)\\) *$");
204
+
156 205
 				GLib.MatchInfo i_ctx = null, i_cause = null, i_human = null;
157
-				//GLib.MatchInfo i_act = null;
206
+				GLib.MatchInfo i_act = null;
207
+				var args = i_args.fetch(1);
158 208
 
159
-				if (! context.match(info.fetch(3),0,out i_ctx)){
160
-					stderr.printf("smd-loop error with no context: %s\n",info.fetch(2));
209
+				if (! context.match(args,0,out i_ctx)){
210
+					stderr.printf("smd-loop error with no context: %s\n",s);
161 211
 					return true;
162 212
 				}
163
-				if (! cause.match(info.fetch(3),0,out i_cause)){
213
+				if (! cause.match(args,0,out i_cause)){
164 214
 					stderr.printf("smd-loop error with no cause: %s\n",s);
165 215
 					return true;
166 216
 				}
167
-				if (! human.match(info.fetch(3),0,out i_human)){
217
+				if (! human.match(args,0,out i_human)){
168 218
 					stderr.printf("smd-loop error with no human: %s\n",s);
169 219
 					return true;
170 220
 				}
171
-				stderr.printf("IMPLEMENT ME\n");
221
+				var has_actions = actions.match(args,0,out i_act);
222
+
223
+				// widget setup
224
+				var l_ctx = builder.get_object("lContext") as Gtk.Label;
225
+				l_ctx.set_text(i_ctx.fetch(1));
226
+				var l_cause = builder.get_object("lCause") as Gtk.Label;
227
+				l_cause.set_text(i_cause.fetch(1));
228
+				if ( i_human.fetch(1) != "required" ){
229
+					stderr.printf("smd-loop giving an avoidable error: %s\n",
230
+						i_human.fetch(1));
231
+					return true;
232
+				}
233
+				bool display_permissions = false;
234
+				bool display_mail = false;
235
+				bool display_commands = false;
236
+				
237
+				if (has_actions) {
238
+					command_hash.remove_all();
239
+					string acts = i_act.fetch(1);
240
+					
241
+					var r_perm = new GLib.Regex(
242
+						"display-permissions\\(([^\\)]+)\\)");
243
+					var r_mail = new GLib.Regex(
244
+						"display-mail\\(([^\\)]+)\\)");
245
+					var r_cmd = new GLib.Regex(
246
+						"run\\(([^\\)]+)\\)");
247
+
248
+					int from = 0;
249
+					for (;acts != null && acts.len() > 0;){
250
+						stderr.printf("--- %s\n",acts);
251
+						MatchInfo i_cmd = null;
252
+						if ( r_perm.match(acts,0,out i_cmd) ){
253
+							display_permissions = true;
254
+							i_cmd.fetch_pos(0,null,out from);
255
+							string file = i_cmd.fetch(1);
256
+							string output = null;
257
+							try {
258
+								GLib.Process.spawn_command_line_sync(
259
+									"ls -ld " + file, out output, null);
260
+								var l = builder.get_object("lPermissions") 
261
+									as Gtk.Label;
262
+								l.set_text(output);
263
+							} catch (GLib.SpawnError e) {
264
+								stderr.printf("Spawning ls: %s\n",e.message);
265
+							}
266
+						} else if ( r_mail.match(acts,0,out i_cmd) ){
267
+							display_mail = true;
268
+							i_cmd.fetch_pos(0,null,out from);
269
+							string file = i_cmd.fetch(1);
270
+							string output = null;
271
+							try {
272
+								GLib.Process.spawn_command_line_sync(
273
+									"cat " + file, out output, null);
274
+								var l = builder.get_object("tvMail") 
275
+									as Gtk.TextView;
276
+								Gtk.TextBuffer b = l.get_buffer();
277
+								b.set_text(output,(int)output.size());
278
+								Gtk.TextIter it,subj;
279
+								b.get_start_iter(out it);
280
+								it.forward_search("Subject:",
281
+									Gtk.TextSearchFlags.TEXT_ONLY,
282
+									out subj,null,null);
283
+								var insert = b.get_insert();
284
+								b.select_range(subj,subj);
285
+								l.scroll_to_mark(insert,0.0,true,0.0,0.0);
286
+							} catch (GLib.SpawnError e) {
287
+								stderr.printf("Spawning ls: %s\n",e.message);
288
+							}
289
+						} else if ( r_cmd.match(acts,0,out i_cmd) ){
290
+							display_commands = true;
291
+							string command = i_cmd.fetch(1);
292
+							i_cmd.fetch_pos(0,null,out from);
293
+							var vb = builder.get_object("vbRun") as Gtk.VBox;
294
+							var hb = new Gtk.HBox(false,10);
295
+							var lbl = new Gtk.Label(command);
296
+							lbl.set_alignment(0.0f,0.5f);
297
+							var but = new Gtk.Button.from_stock("gtk-execute");
298
+							command_hash.insert(but,command);
299
+							but.clicked += (b) => {
300
+								stderr.printf("%s\n",command_hash.lookup(b));
301
+							};
302
+							hb.pack_end(lbl,true,true,0);
303
+							hb.pack_end(but,false,false,0);
304
+							vb.pack_end(hb,true,true,0);
305
+							hb.show_all();
306
+						} else {
307
+							stderr.printf("Unrecognized action: %s\n",acts);
308
+							break;
309
+						}
310
+						acts = acts.substring(from);
311
+					}
312
+				}
313
+
314
+				var x = builder.get_object("fDisplayPermissions") as Gtk.Widget;
315
+				x.visible=display_permissions;
316
+				x = builder.get_object("fDisplayMail") as Gtk.Widget; 
317
+				x.visible=display_mail;
318
+				x = builder.get_object("fRun") as Gtk.Widget; 
319
+				x.visible=display_commands;
320
+				
321
+				events_lock.lock();
322
+				events.append(Event.error(account,host));
323
+				events_lock.unlock();
172 324
 				return false;
173
-			} else if (skip.match(s,0,out info)) {
325
+			} else if (r_skip.match(s,0,out info)) {
174 326
 				return false; // skip that message, not for us
175 327
 			} else {
176 328
 				stderr.printf("unhandled smd-loop message: %s\n",s);
@@ -182,8 +334,8 @@ class smdApplet {
182 334
 
183 335
 	public bool run_smd_loop() {
184 336
 		//string[] cmd = { smd_loop_cmd, "-v" };
185
-		//string[] cmd = {"/bin/echo","default: smd-client: TAGS: statistics::new-mails(1), del-mails(3)"};
186
-		string[] cmd = {"/bin/echo","default: smd-client: TAGS: error::context(foo), probable-cause(dunno), human-intervention(required), sugged-action('foo')"};
337
+		//string[] cmd = {"/bin/echo","default: smd-client@localhost: TAGS: stats::new-mails(1), del-mails(3)"};
338
+		string[] cmd = {"/bin/echo","default: smd-client@foo: TAGS: error::context(testing smd-applet), probable-cause(generated on purpose), human-intervention(required), suggested-action( display-permissions(/home/tassi) display-mail(/home/tassi/Mail/inbox/cur/1096282515.31281_2.garfield:2,S) run(echo a) run(echo b))"};
187 339
 		int child_in;
188 340
 		int child_out;
189 341
 		int child_err;
@@ -220,6 +372,10 @@ class smdApplet {
220 372
 	bool eat_event() {
221 373
 		Event e = null;
222 374
 
375
+		// in error mode no events are processed
376
+		if ( error_mode ) return true;
377
+
378
+		// fetch the event
223 379
 		events_lock.lock();
224 380
 		if ( events.length() > 0) {
225 381
 			e = events.nth(0).data;
@@ -227,6 +383,7 @@ class smdApplet {
227 383
 		}
228 384
 		events_lock.unlock();
229 385
 
386
+		// regular notification
230 387
 		if ( e != null && gconf.get_bool(key_newmail) ){
231 388
 			var not = new Notify.Notification(
232 389
 				"Syncmaildir",e.message,"gtk-about",null);
@@ -236,6 +393,13 @@ class smdApplet {
236 393
 			catch (GLib.Error e) { stderr.printf("%s\n",e.message); }
237 394
 		}
238 395
 
396
+		// error notification
397
+		if ( e != null && e.enter_error_mode ) {
398
+			si.set_from_icon_name("error");
399
+			si.set_blinking(true);
400
+			error_mode = true;
401
+		}
402
+
239 403
 		return true; // re-schedule me please
240 404
 	}
241 405
 	

Loading…
Cancel
Save