1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 /*
4  *  Engrampa
5  *
6  *  Copyright (C) 2001 The Free Software Foundation, Inc.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02110-1301, USA.
21  */
22 
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26 #include <unistd.h>
27 
28 #include <glib.h>
29 
30 #include "file-data.h"
31 #include "file-utils.h"
32 #include "fr-command.h"
33 #include "fr-command-alz.h"
34 #include "glib-utils.h"
35 
36 static void fr_command_alz_class_init  (FrCommandAlzClass *class);
37 static void fr_command_alz_init        (FrCommand         *afile);
38 static void fr_command_alz_finalize    (GObject           *object);
39 
40 /* Parent Class */
41 
42 static FrCommandClass *parent_class = NULL;
43 
44 
45 /* -- list -- */
46 
47 
48 static time_t
mktime_from_string(char * date_s,char * time_s)49 mktime_from_string (char *date_s,
50 		    char *time_s)
51 {
52 	struct tm   tm = {0, };
53 	char      **fields;
54 
55 	/* date */
56 
57 	fields = g_strsplit (date_s, "/", 3);
58 	if (fields[0] != NULL) {
59 		tm.tm_mon = atoi (fields[0]) - 1;
60 		if (fields[1] != NULL) {
61 			tm.tm_mday = atoi (fields[1]);
62 			if (fields[2] != NULL)
63 				tm.tm_year = 100 + atoi (fields[2]);
64 		}
65 	}
66 	g_strfreev (fields);
67 
68 	/* time */
69 
70 	fields = g_strsplit (time_s, ":", 3);
71 	if (fields[0] != NULL) {
72 		tm.tm_hour = atoi (fields[0]);
73 		if (fields[1] != NULL)
74 			tm.tm_min = atoi (fields[1]);
75 	}
76 	g_strfreev (fields);
77 
78 	return mktime (&tm);
79 }
80 
81 
82 static void
process_line(char * line,gpointer data)83 process_line (char     *line,
84 	      gpointer  data)
85 {
86 	FrCommand     *comm = FR_COMMAND (data);
87 	FrCommandAlz  *alz_comm = FR_COMMAND_ALZ (comm);
88 	FileData      *fdata;
89 	char         **fields;
90 	char          *name_field;
91 	char           name_last;
92 	gsize	       name_len;
93 
94 	g_return_if_fail (line != NULL);
95 
96 
97 	if (! alz_comm->list_started) {
98 		if (strncmp (line, "-----", 5 ) == 0 )
99 			alz_comm->list_started = TRUE;
100 		return;
101 	}
102 
103 	if (strncmp (line, "-----", 5 ) == 0) {
104 		alz_comm->list_started = FALSE;
105 		return;
106 
107 	}
108 
109 	if (! alz_comm->list_started)
110 		return;
111 
112 	fdata = file_data_new ();
113 	fields = split_line (line, 5);
114 	fdata->modified = mktime_from_string (fields[0], fields[1]);
115 	fdata->size = g_ascii_strtoull (fields[3], NULL, 10);
116 
117 	name_field = g_strdup (get_last_field (line, 6));
118 	name_len = strlen (name_field);
119 
120 	name_last = name_field[name_len - 1];
121 	fdata->dir = name_last == '\\';
122 	fdata->encrypted = name_last == '*';
123 
124 	if (fdata->dir || fdata->encrypted)
125 		name_field[--name_len] = '\0';
126 
127 	if (*name_field == '/') {
128 		fdata->full_path = g_strdup (name_field);
129 		fdata->original_path = fdata->full_path;
130 	}
131 	else {
132 		fdata->full_path = g_strconcat ("/", name_field, NULL);
133 		fdata->original_path = fdata->full_path + 1;
134 	}
135 
136 	if (fdata->dir) {
137 		char *s;
138 		for (s = fdata->full_path; *s != '\0'; ++s)
139 			if (*s == '\\') *s = '/';
140 		for (s = fdata->original_path; *s != '\0'; ++s)
141 			if (*s == '\\') *s = '/';
142 		fdata->name = dir_name_from_path (fdata->full_path);
143 	}
144 	else {
145 		fdata->name = g_strdup (file_name_from_path (fdata->full_path));
146 	}
147 
148 	fdata->path = remove_level_from_path (fdata->full_path);
149 
150 	if (*fdata->name == 0)
151 		file_data_free (fdata);
152 	else
153 		fr_command_add_file (comm, fdata);
154 
155 	g_free (name_field);
156 	g_strfreev (fields);
157 }
158 
159 
160 static void
add_codepage_arg(FrCommand * comm)161 add_codepage_arg (FrCommand *comm)
162 {
163 	const char  *env_list[] = { "LC_CTYPE", "LC_ALL", "LANG", NULL };
164 	const char **scan;
165 	const char  *arg = "-cp949";
166 
167 	for (scan = env_list; *scan != NULL; ++scan) {
168 		char *env = getenv (*scan);
169 
170 		if (! env)
171 			continue;
172 
173 		if (strstr (env, "UTF-8") ||  strstr (env, "utf-8"))
174 			arg = "-utf8";
175 		else if (strstr (env, "euc") || strstr (env, "EUC"))
176 			arg = "-euc-kr";
177 		else
178 			continue;
179 		break;
180 	}
181 
182 	fr_process_add_arg (comm->process, arg);
183 }
184 
185 
186 static void
add_password_arg(FrCommand * comm,const char * password,gboolean disable_query)187 add_password_arg (FrCommand  *comm,
188 		  const char *password,
189 		  gboolean    disable_query)
190 {
191 	if (password != NULL) {
192 		fr_process_add_arg (comm->process, "-pwd");
193 		fr_process_add_arg (comm->process, password);
194 	}
195 	else if (disable_query) {
196 		fr_process_add_arg (comm->process, "-pwd");
197 		fr_process_add_arg (comm->process, "");
198 	}
199 }
200 
201 
202 static void
list__begin(gpointer data)203 list__begin (gpointer data)
204 {
205 	FrCommandAlz *comm = data;
206 
207 	comm->list_started = FALSE;
208 	comm->invalid_password = FALSE;
209 }
210 
211 
212 static void
fr_command_alz_list(FrCommand * comm)213 fr_command_alz_list (FrCommand  *comm)
214 {
215 	fr_process_set_out_line_func (FR_COMMAND (comm)->process, process_line, comm);
216 
217 	fr_process_begin_command (comm->process, "unalz");
218 	fr_process_set_begin_func (comm->process, list__begin, comm);
219 	fr_process_add_arg (comm->process, "-l");
220 	add_codepage_arg(comm);
221 	fr_process_add_arg (comm->process, comm->filename);
222 	fr_process_end_command (comm->process);
223 	fr_process_use_standard_locale (comm->process, TRUE);
224 	fr_process_start (comm->process);
225 }
226 
227 
228 /* -- extract -- */
229 
230 static void
process_extract_line(char * line,gpointer data)231 process_extract_line (char     *line,
232 		      gpointer  data)
233 {
234 	FrCommand     *comm = FR_COMMAND (data);
235 	FrCommandAlz  *alz_comm = FR_COMMAND_ALZ (comm);
236 
237 	g_return_if_fail (line != NULL);
238 
239 	/* - error check - */
240 
241 	if (strncmp (line, "err code(28) (invalid password)", 31) == 0) {
242 		alz_comm->invalid_password = TRUE;
243 		fr_process_stop (comm->process);
244 		return;
245 	}
246 
247 	if (alz_comm->extract_none && (strncmp (line, "unalziiiing :", 13) == 0)) {
248 		alz_comm->extract_none = FALSE;
249 	}
250 	else if ((strncmp (line, "done..", 6) == 0) && alz_comm->extract_none) {
251 		fr_process_stop (comm->process);
252 		return;
253 	}
254 }
255 
256 
257 static void
fr_command_alz_extract(FrCommand * comm,const char * from_file,GList * file_list,const char * dest_dir,gboolean overwrite,gboolean skip_older,gboolean junk_paths)258 fr_command_alz_extract (FrCommand  *comm,
259 		        const char *from_file,
260 			GList      *file_list,
261 			const char *dest_dir,
262 			gboolean    overwrite,
263 			gboolean    skip_older,
264 			gboolean    junk_paths)
265 {
266 	GList *scan;
267 
268 	FR_COMMAND_ALZ (comm)->extract_none = TRUE;
269 
270 	fr_process_set_out_line_func (FR_COMMAND (comm)->process,
271 				      process_extract_line,
272 				      comm);
273 
274 	fr_process_begin_command (comm->process, "unalz");
275 	if (dest_dir != NULL) {
276 		fr_process_add_arg (comm->process, "-d");
277 		fr_process_add_arg (comm->process, dest_dir);
278 	}
279 	add_codepage_arg (comm);
280 	add_password_arg (comm, comm->password, TRUE);
281 	fr_process_add_arg (comm->process, comm->filename);
282 	for (scan = file_list; scan; scan = scan->next)
283 		fr_process_add_arg (comm->process, scan->data);
284 	fr_process_end_command (comm->process);
285 }
286 
287 
288 static void
fr_command_alz_handle_error(FrCommand * comm,FrProcError * error)289 fr_command_alz_handle_error (FrCommand   *comm,
290 			     FrProcError *error)
291 {
292 	if ((error->type == FR_PROC_ERROR_STOPPED)) {
293 		if  (FR_COMMAND_ALZ (comm)->extract_none ||
294 		     FR_COMMAND_ALZ (comm)->invalid_password ) {
295 			error->type = FR_PROC_ERROR_ASK_PASSWORD;
296 		}
297 	}
298 }
299 
300 
301 const char *alz_mime_type[] = { "application/x-alz", NULL };
302 
303 
304 static const char **
fr_command_alz_get_mime_types(FrCommand * comm)305 fr_command_alz_get_mime_types (FrCommand *comm)
306 {
307 	return alz_mime_type;
308 }
309 
310 
311 static FrCommandCap
fr_command_alz_get_capabilities(FrCommand * comm,const char * mime_type,gboolean check_command)312 fr_command_alz_get_capabilities (FrCommand  *comm,
313 			         const char *mime_type,
314 				 gboolean    check_command)
315 {
316 	FrCommandCap capabilities;
317 
318 	capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES;
319 	if (is_program_available ("unalz", check_command))
320 		capabilities |= FR_COMMAND_CAN_READ;
321 
322 	return capabilities;
323 }
324 
325 
326 static const char *
fr_command_alz_get_packages(FrCommand * comm,const char * mime_type)327 fr_command_alz_get_packages (FrCommand  *comm,
328 			     const char *mime_type)
329 {
330 	return PACKAGES ("unalz");
331 }
332 
333 
334 static void
fr_command_alz_class_init(FrCommandAlzClass * class)335 fr_command_alz_class_init (FrCommandAlzClass *class)
336 {
337         GObjectClass *gobject_class = G_OBJECT_CLASS (class);
338         FrCommandClass *afc;
339 
340         parent_class = g_type_class_peek_parent (class);
341 	afc = (FrCommandClass*) class;
342 
343 	gobject_class->finalize = fr_command_alz_finalize;
344 
345         afc->list             = fr_command_alz_list;
346 	afc->add              = NULL;
347 	afc->delete_           = NULL;
348 	afc->extract          = fr_command_alz_extract;
349 	afc->handle_error     = fr_command_alz_handle_error;
350 	afc->get_mime_types   = fr_command_alz_get_mime_types;
351 	afc->get_capabilities = fr_command_alz_get_capabilities;
352 	afc->get_packages     = fr_command_alz_get_packages;
353 }
354 
355 
356 static void
fr_command_alz_init(FrCommand * comm)357 fr_command_alz_init (FrCommand *comm)
358 {
359 	comm->propAddCanUpdate             = TRUE;
360 	comm->propAddCanReplace            = TRUE;
361 	comm->propExtractCanAvoidOverwrite = FALSE;
362 	comm->propExtractCanSkipOlder      = FALSE;
363 	comm->propExtractCanJunkPaths      = FALSE;
364 	comm->propPassword                 = TRUE;
365 	comm->propTest                     = FALSE;
366 }
367 
368 
369 static void
fr_command_alz_finalize(GObject * object)370 fr_command_alz_finalize (GObject *object)
371 {
372         g_return_if_fail (object != NULL);
373         g_return_if_fail (FR_IS_COMMAND_ALZ (object));
374 
375 	/* Chain up */
376         if (G_OBJECT_CLASS (parent_class)->finalize)
377 		G_OBJECT_CLASS (parent_class)->finalize (object);
378 }
379 
380 
381 GType
fr_command_alz_get_type()382 fr_command_alz_get_type ()
383 {
384         static GType type = 0;
385 
386         if (! type) {
387                 GTypeInfo type_info = {
388 			sizeof (FrCommandAlzClass),
389 			NULL,
390 			NULL,
391 			(GClassInitFunc) fr_command_alz_class_init,
392 			NULL,
393 			NULL,
394 			sizeof (FrCommandAlz),
395 			0,
396 			(GInstanceInitFunc) fr_command_alz_init
397 		};
398 
399 		type = g_type_register_static (FR_TYPE_COMMAND,
400 					       "FrCommandAlz",
401 					       &type_info,
402 					       0);
403         }
404 
405         return type;
406 }
407