1 /*
2  * Copyright (c) 2008-2010 Lu, Chao-Ming (Tetralet).  All rights reserved.
3  *
4  * This file is part of LilyTerm.
5  *
6  * LilyTerm is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * LilyTerm is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with LilyTerm.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "main.h"
21 
22 // for using in socket
23 gboolean single_process = TRUE;
24 gint socket_fd = 0;
25 struct sockaddr_un address = {0};
26 int address_len = 0;
27 GIOChannel *main_channel = NULL;
28 GtkClipboard *selection_clipboard = NULL;
29 GtkClipboard *selection_primary = NULL;
30 
31 // gchar *command_line_path;
32 // gchar **empty_environ;
33 gchar *system_locale_list;
34 gchar *init_LC_CTYPE;
35 gchar *init_encoding;
36 gchar *init_LC_MESSAGES;
37 const gchar *SYSTEM_VTE_CJK_WIDTH_STR = NULL;
38 
39 const gchar *wmclass_name = NULL;
40 gchar *wmclass_class = NULL;
41 const gchar *shell = NULL;
42 const gchar *pwd = NULL;
43 const gchar *home = NULL;
44 
45 GList *window_list = NULL;
46 gchar *profile_dir = NULL;
47 gboolean proc_exist = TRUE;
48 
49 extern gboolean force_to_quit;
50 extern gchar *restricted_locale_message;
51 
52 //
53 // single_process ----------------(N)------------------------------------> new_window() ------>	shutdown_socket_serve()
54 //	|				^					^		  unlink
55 // init_socket_data()			|					|		+ clear_channel()
56 //   socket_fd -------------------(N)---|					|		    g_io_channel_shutdown
57 //   set_fd_non_block ------------(N)---/					|		    (g_io_channel_unref)
58 //	|									|
59 // query_socket()								|
60 //   connect ---------------------(N)-------> init_socket_server() -------------|
61 //	|				^	unlink				|
62 // send_socket()			|	bind -----------------------(N)-|
63 // * g_io_channel_unix_new -------(N)---|	listen ---------------------(N)-|
64 //   g_io_channel_set_encoding ---(N)---|     * g_io_channel_unix_new ------(N)-|
65 //   g_io_channel_set_buffered		|	g_io_channel_set_encoding --(N)-|
66 //   g_io_channel_write_chars ----(N)---|	g_io_add_watch -------------(N)-/
67 //   g_io_channel_flush ----------(N)---/	  |
68 // + clear_channel()				  `---- accept_socket()
69 //     g_io_channel_shutdown				  (condition)
70 //     (g_io_channel_unref)				  accept
71 //	|						  set_fd_non_block
72 //   exit()						* g_io_channel_unix_new
73 //							  g_io_channel_set_encoding
74 //							  g_io_add_watch
75 //							    |
76 //							    `-- read_socket()
77 //								  g_io_channel_read_line
78 //								    new_window()
79 //								+ clear_channel()
80 //								    g_io_channel_shutdown
81 //								    (g_io_channel_unref)
82 //
83 #ifdef UNIT_TEST
fake_main(int argc,char * argv[])84 int fake_main(int   argc,
85 	      char *argv[])
86 #else
87 int main( int   argc,
88 	  char *argv[])
89 #endif
90 {
91 	// command_line_path = argv[0];
92 
93 	// g_debug ("argc = %d", argc);
94 	// print_array ("argv", argv);
95 	// i18n support. We need to support i18n under console, too.
96 	setlocale(LC_ALL, "");
97 	bindtextdomain (BINARY, LOCALEDIR);
98 	bind_textdomain_codeset (BINARY, "UTF-8");
99 	textdomain (BINARY);
100 
101 	const gchar *user_config_dir = g_get_user_config_dir();
102 
103 #ifdef OUT_OF_MEMORY
104 #  undef g_strdup_printf
105 #endif
106 	if (user_config_dir) profile_dir = g_strdup_printf("%s/%s", user_config_dir, BINARY);
107 #ifdef OUT_OF_MEMORY
108 	#define g_strdup_printf(...) NULL
109 #endif
110 
111 	// g_debug("profile_dir = %s", profile_dir);
112 	proc_exist = g_file_test("/proc", G_FILE_TEST_EXISTS);
113 
114 	if (proc_exist)
115 	{
116 		gboolean proc_is_exist = FALSE;
117 		GDir *dir  = g_dir_open ("/proc", 0, NULL);
118 		if (dir)
119 		{
120 			const gchar *entry = g_dir_read_name(dir);
121 			if (entry) proc_is_exist = TRUE;
122 		}
123 		g_dir_close(dir);
124 		// g_debug ("Got proc_is_exist = %d", proc_is_exist);
125 		proc_exist = proc_is_exist;
126 	}
127 
128 	shell = g_getenv("SHELL");
129 	if (shell==NULL) shell = "";
130 
131 	pwd = g_getenv("PWD");
132 	// pwd = g_get_current_dir();
133 #ifdef SAFEMODE
134 	if (pwd==NULL) pwd = g_strdup("");
135 #endif
136 	// g_debug("Got $PWD = %s", pwd);
137 	home = g_getenv("HOME");
138 	if (home==NULL) home = "";
139 	// g_debug("Get $HOME = %s", home);
140 
141 	// deal the command line options
142 	command_option(argc, argv);
143 	if (wmclass_name==NULL) wmclass_name = g_getenv("RESOURCE_NAME");
144 	if (wmclass_name==NULL) wmclass_name = "";
145 	if (wmclass_class==NULL) wmclass_class = "";
146 	// g_debug("Got wmclass_name = %s, wmclass_class = %s", wmclass_name, wmclass_class);
147 
148 	// init the gtk+2 engine
149 #ifndef UNIT_TEST
150 	gtk_init(&argc, &argv);
151 #endif
152 	// FIXME: we should get the single_process from profile. Current is command-line option only.
153 	if (single_process)
154 	{
155 		// init socket data
156 		if (init_socket_data())
157 		{
158 			// trying to connect to an existing LilyTerm
159 			if (query_socket())
160 			{
161 				// success, sent the argc/argv to socket then quit
162 				// g_debug("A LilyTerm socket server is exist already. exiting...");
163 				if (send_socket(argc, argv, TRUE))
164 				{
165 					g_free(profile_dir);
166 					exit (0);
167 				}
168 			}
169 			// no LilyTerm exist. create a socket server
170 			// g_debug("Creating a LilyTerm socket server...");
171 			init_socket_server();
172 			g_atexit((GVoidFunc)shutdown_socket_server);
173 		}
174 	}
175 
176 	// start LilyTerm
177 
178 	// empty_environ = g_strsplit("", " ", -1);
179 	extern gchar **environ;
180 	// print_array("main(): environ", environ);
181 	gchar *environ_str = convert_array_to_string(environ, '\t');
182 	window_list = NULL;
183 	// g_debug("Got environ_str (in main.c) = %s", environ_str);
184 	selection_clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
185 	selection_primary = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
186 	system_locale_list = get_locale_list();
187 	// g_debug("Got system_locale_list = %s", system_locale_list);
188 	init_LC_CTYPE = g_strdup(get_default_lc_data(LC_CTYPE));
189 	// g_debug("Got init_LC_CTYPE = %s", init_LC_CTYPE);
190 	init_LC_MESSAGES = g_strdup(get_default_lc_data(LC_MESSAGES));
191 	// g_debug("init_LC_MESSAGES = %s", init_LC_MESSAGES);
192 	init_encoding = (gchar *)get_encoding_from_locale(NULL);
193 	if (! compare_strings(init_encoding, "ANSI_X3.4-1968", TRUE))
194 	{
195 		g_free(init_encoding);
196 		init_encoding = g_strdup("UTF-8");
197 	}
198 	// g_debug("init_encoding = %s", init_encoding);
199 	SYSTEM_VTE_CJK_WIDTH_STR = g_getenv("VTE_CJK_WIDTH");
200 	// g_debug ("Got SYSTEM_VTE_CJK_WIDTH_STR = %s", SYSTEM_VTE_CJK_WIDTH_STR);
201 	// FIXME: signal(SIGCHLD, SIG_IGN);
202 	// The first window of LilyTerm
203 
204 	// g_debug("Got original encoding = %s", get_encoding_from_locale(NULL));
205 	//GtkNotebook *new_window(int argc,
206 	//			char *argv[],
207 	//			gchar *shell,
208 	//			gchar *environment,
209 	//			gchar *locale_list,
210 	//			gchar *PWD,
211 	//			gchar *HOME,
212 	//			gchar *VTE_CJK_WIDTH_STR,
213 	//			gboolean VTE_CJK_WIDTH_STR_overwrite_profile,
214 	//			gchar *wmclass_name,
215 	//			gchar *wmclass_class,
216 	//			gchar *user_environ,
217 	//			gchar *encoding,
218 	//			gboolean encoding_overwrite_profile,
219 	//			gchar *lc_messages,
220 	//			struct Window *win_data_orig,
221 	//			struct Page *page_data_orig)
222 
223 	if ((new_window(argc,
224 			argv,
225 			(gchar *) shell,
226 			environ_str,
227 			system_locale_list,
228 			(gchar *) pwd,
229 			(gchar *) home,
230 			SYSTEM_VTE_CJK_WIDTH_STR,
231 			FALSE,
232 			wmclass_name,
233 			wmclass_class,
234 			NULL,
235 			init_encoding,
236 			FALSE,
237 			init_LC_MESSAGES,
238 			NULL,
239 			NULL)) ||
240 	     window_list)
241 	{
242 		// The argv of "main" LilyTerm can't be free.
243 		// Set it to NULL here to avoid double_free().
244 		argv=NULL;
245 		// g_debug("gtk_main_level = %d", gtk_main_level());
246 		if (! gtk_main_level())
247 			gtk_main();
248 	}
249 #ifdef DETAIL
250 	else
251 	{
252 //		g_debug("Got window_list = %p", window_list);
253 //		GList *win_list = window_list;
254 //		gint i=0;
255 //
256 //		while (win_list)
257 //		{
258 //			g_debug("Got %d win_data = %p", ++i, win_list->data);
259 //			win_list = win_list->next;
260 //		}
261 		g_debug("??? The creation of first window is FAIL!!!");
262 	}
263 #endif
264 	extern struct KeyValue system_keys[KEYS];
265 	gint i;
266 	// g_debug("Clear function key data!!");
267 	for (i=KEY_SWITCH_TO_TAB_1; i<=KEY_SWITCH_TO_TAB_12; i++)
268 	{
269 		g_free(system_keys[i].name);
270 		g_free(system_keys[i].topic);
271 		g_free(system_keys[i].comment);
272 		g_free(system_keys[i].translation);
273 #ifdef UNIT_TEST
274 		system_keys[i].name = NULL;
275 		system_keys[i].topic = NULL;
276 		system_keys[i].comment = NULL;
277 		system_keys[i].translation = NULL;
278 #endif
279 	}
280 
281 	// g_free(pwd);
282 	// g_strfreev(empty_environ);
283 	g_free(environ_str);
284 	g_free(init_encoding);
285 	g_free(system_locale_list);
286 	g_free(profile_dir);
287 	g_free(restricted_locale_message);
288 	g_list_free(window_list);
289 	g_free(init_LC_CTYPE);
290 	g_free(init_LC_MESSAGES);
291 #ifdef UNIT_TEST
292 	// empty_environ = NULL;
293 	environ_str = NULL;
294 	init_encoding = NULL;
295 	system_locale_list = NULL;
296 	profile_dir = NULL;
297 	restricted_locale_message = NULL;
298 	window_list = NULL;
299 	init_LC_CTYPE = NULL;
300 	init_LC_MESSAGES = NULL;
301 #endif
302 	return 0;
303 }
304 
305 
306 // it will return TRUE if init socket data successfully
init_socket_data()307 gboolean init_socket_data()
308 {
309 #ifdef DETAIL
310 	g_debug("! Launch init_socket_data() to init LilyTerm socket!");
311 #endif
312 	GError *error = NULL;
313 
314 	// clean data first
315 	bzero(&address, sizeof(address));
316 	// init the address of socket
317 	address.sun_family = AF_UNIX;
318 
319 	const gchar *tmp_dir = g_get_tmp_dir();
320 #ifdef SAFEMODE
321 	if (tmp_dir)
322 	{
323 #endif
324 		gchar *display = gdk_get_display();
325 #if defined(DEVELOP)
326 		g_snprintf(address.sun_path, UNIX_PATH_MAX, "%s/.%s_dev_%s%s",
327 			   tmp_dir ,BINARY, g_get_user_name(), display);
328 #elif defined(DEBUG)
329 		g_snprintf(address.sun_path, UNIX_PATH_MAX, "%s/.%s_dbg_%s%s",
330 			   tmp_dir ,BINARY, g_get_user_name(), display);
331 #else
332 		g_snprintf(address.sun_path, UNIX_PATH_MAX, "%s/.%s_%s%s",
333 			   tmp_dir ,BINARY, g_get_user_name(), display);
334 #endif
335 		g_free(display);
336 #ifdef SAFEMODE
337 	}
338 #endif
339 	address.sun_path[UNIX_PATH_MAX-1] = address.sun_path[UNIX_PATH_MAX-2] = '\0';
340 	// g_debug("The socket file is %s", address.sun_path);
341 	address_len = sizeof(address);
342 
343 	// init socket
344 	socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
345 	if (socket_fd < 0)
346 		// main_channel is NULL, so that we don't need to launch clear_channel()
347 		return socket_fault(1, error, NULL, FALSE);
348 
349 	// set this socket is non-block
350 	return set_fd_non_block(&socket_fd);
351 }
352 
353 // it will return TRUE if scucceed
set_fd_non_block(gint * fd)354 gboolean set_fd_non_block(gint *fd)
355 {
356 #ifdef DETAIL
357 	if (fd)
358 		g_debug("! Launch set_fd_non_block() with fd = %d!", *fd);
359 	else
360 		g_debug("! Launch set_fd_non_block() with fd = (%p)!", fd);
361 #endif
362 #ifdef SAFEMODE
363 	if (fd==NULL) return FALSE;
364 #endif
365 	GError *error = NULL;
366 	gint flags = fcntl(*fd, F_GETFL, 0);
367 	if (fcntl(*fd, F_SETFL, O_NONBLOCK|flags) < 0)
368 		// main_channel is NULL, so that we don't need to launch clear_channel()
369 		return socket_fault(8, error, NULL, FALSE);
370 	return TRUE;
371 }
372 
373 // it will return TRUE if scucceed
query_socket()374 gboolean query_socket()
375 {
376 #ifdef DETAIL
377 	g_debug("! Launch query_socket() to connect to an existing LilyTerm !");
378 #endif
379 	GError *error = NULL;
380 
381 	if (connect(socket_fd, (struct sockaddr *)&address, address_len) < 0)
382 		// main_channel is NULL, so that we don't need to launch clear_channel()
383 		return socket_fault(2, error, NULL, FALSE);
384 	return TRUE;
385 }
386 
387 // it will return TRUE if scucceed
send_socket(int argc,char * argv[],gboolean wait)388 gboolean send_socket( int   argc,
389 		      char *argv[],
390 		      gboolean wait)
391 {
392 #ifdef DETAIL
393 	g_debug("! Launch send_socket() to send data to the exiting LilyTerm !");
394 	g_debug("! send_socket() argc = %d, wait = %d", argc, wait);
395 	print_array("! send_socket() argv", argv);
396 #endif
397 
398 	GError *error = NULL;
399 	gsize len;
400 	extern gchar **environ;
401 
402 	gchar *locale_list = get_locale_list();
403 
404 	const gchar *VTE_CJK_WIDTH_STR = g_getenv("VTE_CJK_WIDTH");
405 	// VTE_CJK_WIDTH can't = NULL
406 	if (VTE_CJK_WIDTH_STR == NULL) VTE_CJK_WIDTH_STR = "";
407 
408 	// g_debug("Got LOCALE = %s in send_socket...", get_encoding_from_locale(NULL));
409 	gchar *encoding = get_encoding_from_locale(NULL);
410 	if (! compare_strings(encoding, "ANSI_X3.4-1968", TRUE))
411 	{
412 		g_free(encoding);
413 		encoding = g_strdup("UTF-8");
414 	}
415 	// g_debug("Got encoding = %s in send_socket...", encoding);
416 	gchar *lc_messages = g_strdup(get_default_lc_data(LC_MESSAGES));
417 
418 	gchar *environ_str = convert_array_to_string(environ, '\t');
419 	// print_array("! send_socket() environ", environ);
420 	// g_debug("environ_str = %s", environ_str);
421 	gchar *argv_str = convert_array_to_string(argv, '\x10');
422 #ifdef SAFEMODE
423 	gboolean need_free_argv_str = TRUE;
424 	if (argv_str==NULL) argv_str=g_strdup("");
425 	if (argv_str==NULL)
426 	{
427 		need_free_argv_str = FALSE;
428 		argv_str = "";
429 	}
430 #endif
431 	// g_debug("argv_str = %s", argv_str);
432 
433 	// g_debug("SEND DATA: SOCKET_DATA_VERSION = %s", SOCKET_DATA_VERSION);
434 	// g_debug("SEND DATA: locale_list = %s", locale_list);
435 	// g_debug("SEND DATA: encoding = %s", encoding);
436 	// g_debug("SEND DATA: PWD = %s", PWD);
437 	// g_debug("SEND DATA: VTE_CJK_WIDTH_STR = %s", VTE_CJK_WIDTH_STR);
438 	// g_debug("SEND DATA: wmclass_name = %s", wmclass_name);
439 	// g_debug("SEND DATA: wmclass_class = %s", wmclass_class);
440 	// g_debug("SEND DATA: environ_str = %s", environ_str);
441 	// g_debug("SEND DATA: argv_str = %s", argv_str);
442 	//	      0			  1	2	    3	     4		 5   6	  7		    8		 9	       10      11
443 	// send data: SOCKET_DATA_VERSION SHELL LOCALE_LIST ENCODING LC_MESSAGES PWD HOME VTE_CJK_WIDTH_STR wmclass_name wmclass_class ENVIRON ARGV
444 	//				  0	1     2	    3	  4	5     6	    7	  8	9     10    11
445 	gchar *arg_str = g_strdup_printf("%s\x10%s\x10%s\x10%s\x10%s\x10%s\x10%s\x10%s\x10%s\x10%s\x10%s\x10%s\x10",
446 			 		 SOCKET_DATA_VERSION,
447 					 shell,
448 					 locale_list,
449 					 encoding,
450 					 lc_messages,
451 					 pwd,
452 					 home,
453 					 VTE_CJK_WIDTH_STR,
454 					 wmclass_name,
455 					 wmclass_class,
456 					 environ_str,
457 					 argv_str);
458 	// g_debug("arg_str = %s", arg_str);
459 	g_free(locale_list);
460 	g_free(encoding);
461 	g_free(lc_messages);
462 	g_free(environ_str);
463 #ifdef SAFEMODE
464 	if (need_free_argv_str)
465 #endif
466 		g_free(argv_str);
467 
468 	// write data!
469 #ifdef SAFEMODE
470 	if (fcntl(socket_fd, F_GETFL) < 0) return FALSE;
471 #endif
472 	GIOChannel *channel = g_io_channel_unix_new(socket_fd);
473 	// main_channel is NULL, so that we don't need to launch clear_channel()
474 	if (!channel) return socket_fault(12, NULL, NULL, FALSE);
475 	// set the channel to read binary file
476 	if (g_io_channel_set_encoding(channel, NULL, &error) == G_IO_STATUS_ERROR)
477 		return socket_fault(9, error, channel, TRUE);
478 	g_io_channel_set_buffered (channel, FALSE);
479 
480 #ifdef SAFEMODE
481 	if ((arg_str == NULL) ||
482 	    (g_io_channel_write_chars(channel, arg_str, -1, &len, &error)==G_IO_STATUS_ERROR))
483 #else
484 	if (g_io_channel_write_chars(channel, arg_str, -1, &len, &error)==G_IO_STATUS_ERROR)
485 #endif
486 		// main_channel is NULL, so that we don't need to launch clear_channel()
487 		return socket_fault(11, error, channel, TRUE);
488 	// flush writing datas
489 	if (g_io_channel_flush(channel, &error) == G_IO_STATUS_ERROR)
490 		// main_channel is NULL, so that we don't need to launch clear_channel()
491 		return socket_fault(13, error, channel, TRUE);
492 
493 	g_free(arg_str);
494 
495 	// So far so good. shutdown and clear channel!
496 	clear_channel(channel, TRUE);
497 
498 	// FIXME: sleep for 1 sec to wait the socket server. any better idea?
499 	if (wait) sleep(1);
500 
501 	return TRUE;
502 }
503 
504 // it will return TRUE if succeed
init_socket_server()505 gboolean init_socket_server()
506 {
507 #ifdef DETAIL
508 	g_debug("! Launch init_socket_server() to init a LilyTerm socket server !");
509 #endif
510 	GError *error = NULL;
511 
512 	// clear the prev file
513 	if (address.sun_path) unlink(address.sun_path);
514 
515 	// bind the socket on a file
516 	if (bind(socket_fd, (struct sockaddr *)&address, address_len) < 0)
517 		// main_channel is NULL, so that we don't need to launch clear_channel()
518 		return socket_fault(3, error, NULL, FALSE);
519 
520 	// create socket queue
521 	if (listen(socket_fd, 5) < 0)
522 		// main_channel is NULL, so that we don't need to launch clear_channel()
523 		return socket_fault(4, error, NULL, FALSE);
524 
525 	main_channel = g_io_channel_unix_new(socket_fd);
526 	if (!main_channel) return socket_fault(12, NULL, NULL, FALSE);
527 	// set the channel to read binary file
528 	if (g_io_channel_set_encoding(main_channel, NULL, &error) == G_IO_STATUS_ERROR)
529 		return socket_fault(9, error, main_channel, TRUE);
530 
531 	// if any request from client, call accept_socket().
532 	// the channel will be clean when main_quit()
533 	if ( ! g_io_add_watch ( main_channel, G_IO_IN|G_IO_HUP, (GIOFunc)accept_socket, NULL))
534 		return socket_fault(5, error, NULL, TRUE);
535 
536 	return TRUE;
537 }
538 
539 // it will return TRUE if succeed
accept_socket(GIOChannel * source,GIOCondition condition,gpointer user_data)540 gboolean accept_socket(GIOChannel *source, GIOCondition condition, gpointer user_data)
541 {
542 #ifdef DETAIL
543 	g_debug("! Launch accept_socket() to accept the request from client !");
544 #endif
545 #ifdef SAFEMODE
546 	if (source==NULL) return FALSE;
547 #endif
548 
549 	GError *error = NULL;
550 
551 	if (condition & G_IO_HUP)
552 		return socket_fault(6, error, source, FALSE);
553 	else
554 	{
555 		gint read_fd = accept(g_io_channel_unix_get_fd(source), NULL, NULL);
556 		if (read_fd < 0)
557 			return socket_fault(1, error, source, FALSE);
558 		if ( ! set_fd_non_block(&read_fd)) return FALSE;
559 
560 		GIOChannel* channel = g_io_channel_unix_new(read_fd);
561 		// channel is NULL, so that we don't need to launch clear_channel()
562 		if (!channel) return socket_fault(12, NULL, channel, FALSE);
563 		// set the channel to read binary file
564 		if (g_io_channel_set_encoding(channel, NULL, &error) == G_IO_STATUS_ERROR)
565 			return socket_fault(9, error, channel, TRUE);
566 
567 		// read the data that client sent.
568 		if ( ! g_io_add_watch(channel, G_IO_HUP, read_socket, NULL))
569 			return socket_fault(5, error, channel, TRUE);
570 	}
571 	return TRUE;
572 }
573 
574 // it will return TRUE if succeed
read_socket(GIOChannel * channel,GIOCondition condition,gpointer user_data)575 gboolean read_socket(GIOChannel *channel, GIOCondition condition, gpointer user_data)
576 {
577 #ifdef DETAIL
578 	g_debug("! Launch read_socket() to read data !");
579 #endif
580 #ifdef SAFEMODE
581 	if (channel==NULL) return FALSE;
582 #endif
583 
584 	GError *error = NULL;
585 	gchar *data = NULL, **datas;
586 	gsize len = 0;
587 	gsize term;
588 
589 	if (g_io_channel_read_line (channel, &data, &len, &term, &error) == G_IO_STATUS_ERROR)
590 		return socket_fault(7, error, channel, TRUE);
591 	// g_debug("Read %ld bytes from Lilyterm socket: '%s'", len, data);
592 	if (len > 0)
593 	{
594 		//	     0			 1     2	   3	    4		5   6	 7		   8		9	      10      11
595 		// get data: SOCKET_DATA_VERSION SHELL LOCALE_LIST ENCODING LC_MESSAGES PWD HOME VTE_CJK_WIDTH_STR wmclass_name wmclass_class ENVIRON ARGV
596 		// clear '\n' at the end of data[]
597 		data[len-1] = 0;
598 
599 		datas = split_string(data, "\x10", 12);
600 		// g_debug("The SOCKET_DATA_VERSION = %s ,and the data sent via socket is %s",
601 		//	   SOCKET_DATA_VERSION, datas[0]);
602 		if ((datas==NULL) || compare_strings(SOCKET_DATA_VERSION, datas[0], TRUE))
603 		{
604 			// The SOCKET_DATA_VERSION != the data sent via socket
605 			gchar *received_socket_version = NULL;
606 			if (datas) received_socket_version = datas[0];
607 
608 			gchar *message = g_strdup_printf(_("The data got from socket seems incorrect.\n\n"
609 							   "\tReceived socket version: %s\n"
610 							   "\tExpected socket version: %s\n\n"
611 							   "If you just updated %s recently,\n"
612 							   "Please close all the windows of %s and try again."),
613 							   received_socket_version, SOCKET_DATA_VERSION,
614 							   PACKAGE, PACKAGE);
615 			error_dialog(NULL,
616 				     _("The format of socket data is out of date"),
617 				     "The format of socket data is out of date",
618 				     GTK_STOCK_DIALOG_ERROR,
619 				     message,
620 				     NULL);
621 			g_free(message);
622 		}
623 		else
624 		{
625 			gchar **argv = split_string(datas[11], "\x10", -1);
626 			gint argc = 0;
627 			if (argv)
628 				while (argv[argc])
629 					argc ++;
630 
631 			// g_debug("Final:");
632 			// g_debug("\targc =%d", argc);
633 			// print_array("\targv", argv);
634 			// g_debug("\tSHELL = %s", datas[1]);
635 			// g_debug("\tenvironments = %s", datas[10]);
636 			// g_debug("\tlocale_list = %s", datas[2]);
637 			// g_debug("\tPWD = %s", datas[5]);
638 			// g_debug("\tHOME = %s", datas[6]);
639 			// g_debug("\tVTE_CJK_WIDTH_STR = %s", datas[7]);
640 			// g_debug("\twmclass_name = %s", datas[8]);
641 			// g_debug("\twmclass_class= %s", datas[9]);
642 			// g_debug("\tencoding = %s", datas[3]);
643 			// g_debug("\tlc_messages = %s", datas[4]);
644 
645 			//GtkNotebook *new_window(int argc,
646 			//			char *argv[],
647 			//			gchar *shell,					// 1
648 			//			gchar *environment,				// 10
649 			//			gchar *locale_list,				// 2
650 			//			gchar *PWD,					// 5
651 			//			gchar *HOME,					// 6
652 			//			gchar *VTE_CJK_WIDTH_STR,			// 7
653 			//			gboolean VTE_CJK_WIDTH_STR_overwrite_profile,
654 			//			gchar *wmclass_name,				// 8
655 			//			gchar *wmclass_class,				// 9
656 			//			gchar *user_environ,
657 			//			gchar *encoding,				// 3
658 			//			gboolean encoding_overwrite_profile,
659 			//			gchar *lc_messages,				// 4
660 			//			struct Window *win_data_orig,
661 			//			struct Page *page_data_orig)
662 
663 			new_window(argc,
664 				   argv,
665 				   datas[1],
666 				   datas[10],
667 				   datas[2],
668 				   datas[5],
669 				   datas[6],
670 				   datas[7],
671 				   FALSE,
672 				   datas[8],
673 				   datas[9],
674 				   NULL,
675 				   datas[3],
676 				   FALSE,
677 				   datas[4],
678 				   NULL,
679 				   NULL);
680 			g_strfreev(argv);
681 		}
682 		g_strfreev(datas);
683 		data[len-1] = '\n';
684 		g_free(data);
685 	}
686 	clear_channel(channel, TRUE);
687 	// return FALSE means this connection is finish.
688 	return FALSE;
689 }
690 
691 // it will always return FALSE
socket_fault(int type,GError * error,GIOChannel * channel,gboolean unref)692 gboolean socket_fault(int type, GError *error, GIOChannel *channel, gboolean unref)
693 {
694 #ifdef DETAIL
695 	g_debug("! Launch socket_fault() to show the error message !");
696 #endif
697 #ifdef UNIT_TEST
698 #  define G_WARNING g_message
699 #else
700 #  define G_WARNING g_warning
701 #endif
702 	switch (type)
703 	{
704 		case 1:
705 			G_WARNING("Error when create %s socket(%s): %s",
706 				  PACKAGE, address.sun_path, g_strerror (errno));
707 			break;
708 		case 2:
709 			g_message("Can NOT connect to a existing %s socket!", PACKAGE);
710 			break;
711 		case 3:
712 			G_WARNING("Can NOT bind on the socket!");
713 			break;
714 		case 4:
715 			G_WARNING("Can NOT listen on the socket!");
716 			break;
717 		case 5:
718 			G_WARNING("Can not watch on the socket!");
719 			break;
720 		case 6:
721 			G_WARNING("Error when accepting client request via socket!");
722 			break;
723 		case 7:
724 			G_WARNING("Error when reading the data client sent via socket!");
725 			break;
726 		case 8:
727 			G_WARNING("Error when running fcntl command on socket!");
728 			break;
729 		case 9:
730 #ifdef SAFEMODE
731 			if (error)
732 #endif
733 				G_WARNING("Error when setting the encoding of channel: %s", error->message);
734 			break;
735 		case 10:
736 #ifdef SAFEMODE
737 			if (error)
738 #endif
739 				G_WARNING("Error when shutdowning a channel: %s", error->message);
740 			break;
741 		case 11:
742 #ifdef SAFEMODE
743 			if (error)
744 #endif
745 				G_WARNING("Error when writing data to the channel: %s", error->message);
746 			break;
747 		case 12:
748 			G_WARNING("Can NOT create a channel for this socket");
749 			break;
750 		case 13:
751 #ifdef SAFEMODE
752 			if (error)
753 #endif
754 				G_WARNING("Error when flushing the write buffer for the channel: %s", error->message);
755 			break;
756 		default:
757 #ifdef FATAL
758 			print_switch_out_of_range_error_dialog("socket_fault", "type", type);
759 #endif
760 			break;
761 	}
762 	if (error) g_clear_error (&error);
763 	clear_channel(channel, unref);
764 #ifdef UNIT_TEST
765 #  undef G_WARNING
766 #endif
767 	return FALSE;
768 }
769 
770 // it will return TRUE if scucceed
clear_channel(GIOChannel * channel,gboolean unref)771 gboolean clear_channel(GIOChannel *channel, gboolean unref)
772 {
773 #ifdef DETAIL
774 	g_debug("! Launch clear_channel() to clear channel data !");
775 #endif
776 	if (channel == NULL) return TRUE;
777 
778 	gboolean return_value = TRUE;
779 	GError *error = NULL;
780 
781 	if (g_io_channel_shutdown(channel, TRUE, &error) == G_IO_STATUS_ERROR)
782 		return_value = socket_fault(10, error, NULL, FALSE);
783 
784 	if (return_value && unref)
785 	{
786 		g_io_channel_unref(channel);
787 		channel = NULL;
788 	}
789 
790 	return return_value;
791 }
792 
793 // It should always return 0.
shutdown_socket_server(gpointer data)794 gint shutdown_socket_server(gpointer data)
795 {
796 #ifdef DETAIL
797 	g_debug("! Launch shutdown_socket_server() to shutdown the LilyTerm socket server!");
798 #endif
799 	if (main_channel) clear_channel(main_channel, TRUE);
800 	if (address.sun_path) unlink(address.sun_path);
801 	return 0;
802 }
803 
main_quit(GtkWidget * widget,struct Window * win_data)804 void main_quit(GtkWidget *widget, struct Window *win_data)
805 {
806 #ifdef DETAIL
807 	g_debug("! Launch main_quit() with win_data = %p!", win_data);
808 #endif
809 	// g_debug("Total window = %d", g_list_length(window_list));
810 	if (g_list_length(window_list)==1)
811 	{
812 #ifdef SAFEMODE
813 		// g_debug ("main_quit(): win_data==NULL, call gtk_main_quit()");
814 		if (win_data==NULL) return quit_gtk();
815 #endif
816 		window_quit(win_data->window, NULL, win_data);
817 	}
818 	else
819 	{
820 		GString *all_process_list = g_string_new(NULL);
821 		GString *child_process_list;
822 		GList *win_list = window_list;
823 		struct Window *temp_win_data;
824 		gint i = 1;
825 		while (win_list)
826 		{
827 			temp_win_data = win_list->data;
828 			child_process_list = close_multi_tabs(temp_win_data, i);
829 #ifdef SAFEMODE
830 			if (child_process_list)
831 #endif
832 				g_string_append (all_process_list, child_process_list->str);
833 			g_string_free(child_process_list, TRUE);
834 			win_list = win_list->next;
835 			i++;
836 		}
837 
838 		// g_debug("Got all_process_list =%s", all_process_list->str);
839 #ifdef SAFEMODE
840 		if ((all_process_list==NULL) || (all_process_list->len==0) ||
841 		    (display_child_process_dialog (all_process_list, win_data,
842 						   CONFIRM_TO_EXIT_WITH_CHILD_PROCESS)))
843 #else
844 		if ((all_process_list->len==0) ||
845 		    (display_child_process_dialog (all_process_list, win_data,
846 		    				   CONFIRM_TO_EXIT_WITH_CHILD_PROCESS)))
847 #endif
848 		{
849 			force_to_quit = TRUE;
850 			// g_debug ("main_quit(): call gtk_main_quit()");
851 			quit_gtk();
852 		}
853 		g_string_free(all_process_list, TRUE);
854 	}
855 }
856 
quit_gtk()857 void quit_gtk()
858 {
859 #ifdef DETAIL
860 	g_debug("! Launch quit_gtk()");
861 #endif
862 	if (gtk_main_level()) gtk_main_quit();
863 }
864 
get_locale_list()865 gchar *get_locale_list()
866 {
867 #ifdef DETAIL
868 	g_debug("! Launch get_locale_list()!");
869 #endif
870 #ifdef OUT_OF_MEMORY
871 #  undef g_getenv
872 #endif
873 	return join_strings_to_string(' ',
874 				      14,
875 				      g_getenv("LANG"),
876 				      g_getenv("LC_CTYPE"),
877 				      g_getenv("LC_NUMERIC"),
878 				      g_getenv("LC_TIME"),
879 				      g_getenv("LC_COLLATE"),
880 				      g_getenv("LC_MONETARY"),
881 				      g_getenv("LC_MESSAGES"),
882 				      g_getenv("LC_PAPER"),
883 				      g_getenv("LC_NAME"),
884 				      g_getenv("LC_ADDRESS"),
885 				      g_getenv("LC_TELEPHONE"),
886 				      g_getenv("LC_MEASUREMENT"),
887 				      g_getenv("LC_IDENTIFICATION"),
888 				      g_getenv("LC_ALL"));
889 #ifdef OUT_OF_MEMORY
890 	#define g_getenv(x) NULL
891 #endif
892 }
893 
894 //// The returned GString should be freed when no longer needed.
895 //GString *convert_string_array_to_0x9_separated_gstring (gchar **string_array)
896 //{
897 //	gint i = 0;
898 //	GString *string = g_string_new("");
899 //
900 //	if (string_array!=NULL)
901 //	{
902 //		while (string_array[i]!=NULL)
903 //		{
904 //			// g_debug("%d: %s", i, string_array[i]);
905 //			g_string_append_printf(string, "%s\x10", string_array[i]);
906 //			i++;
907 //		}
908 //	}
909 //	return string ;
910 //}
911