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 
27 #include <glib.h>
28 
29 #include "file-data.h"
30 #include "file-utils.h"
31 #include "glib-utils.h"
32 #include "fr-command.h"
33 #include "fr-command-lha.h"
34 
35 static void fr_command_lha_class_init  (FrCommandLhaClass *class);
36 static void fr_command_lha_init        (FrCommand         *afile);
37 static void fr_command_lha_finalize    (GObject           *object);
38 
39 /* Parent Class */
40 
41 static FrCommandClass *parent_class = NULL;
42 
43 
44 /* -- list -- */
45 
46 static time_t
mktime_from_string(char * month,char * mday,char * time_or_year)47 mktime_from_string (char *month,
48 		    char *mday,
49 		    char *time_or_year)
50 {
51 	static char  *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
52 				   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
53 	struct tm     tm = {0, };
54 	char        **fields;
55 
56 	tm.tm_isdst = -1;
57 
58 	/* date */
59 
60 	if (month != NULL) {
61 		int i;
62 		for (i = 0; i < 12; i++)
63 			if (strcmp (months[i], month) == 0) {
64 				tm.tm_mon = i;
65 				break;
66 			}
67 	}
68 	tm.tm_mday = atoi (mday);
69 	if (strchr (time_or_year, ':') == NULL)
70 		tm.tm_year = atoi (time_or_year) - 1900;
71 	else {
72 		time_t     now;
73 		struct tm *tm_now;
74 
75 		now = time (NULL);
76 		tm_now = localtime (&now);
77 		if (tm_now != NULL)
78 			tm.tm_year = tm_now->tm_year;
79 
80 		/* time */
81 
82 		fields = g_strsplit (time_or_year, ":", 2);
83 		if (fields[0] != NULL) {
84 			tm.tm_hour = atoi (fields[0]);
85 			if (fields[1] != NULL)
86 				tm.tm_min = atoi (fields[1]);
87 		}
88 		g_strfreev (fields);
89 	}
90 
91 	return mktime (&tm);
92 }
93 
94 
95 static char **
split_line_lha(char * line)96 split_line_lha (char *line)
97 {
98 	char       **fields;
99 	int          n_fields = 7;
100 	const char  *scan, *field_end;
101 	int          i;
102 
103 	fields = g_new0 (char *, n_fields + 1);
104 	fields[n_fields] = NULL;
105 
106 	i = 0;
107 
108 	if (strncmp (line, "[MS-DOS]", 8) == 0) {
109 		fields[i++] = g_strdup ("");
110 		fields[i++] = g_strdup ("");
111 		line += strlen ("[MS-DOS]");
112 	}
113 	else if (strncmp (line, "[generic]", 9) == 0) {
114 		fields[i++] = g_strdup ("");
115 		fields[i++] = g_strdup ("");
116 		line += strlen ("[generic]");
117 	}
118 	else if (strncmp (line, "[unknown]", 9) == 0) {
119 		fields[i++] = g_strdup ("");
120 		fields[i++] = g_strdup ("");
121 		line += strlen ("[unknown]");
122 	}
123 	else if (strncmp (line, "[Amiga]", 7) == 0) {
124 		fields[i++] = g_strdup ("");
125 		fields[i++] = g_strdup ("");
126 		line += strlen ("[Amiga]");
127 	}
128 
129 	scan = eat_spaces (line);
130 	for (; i < n_fields; i++) {
131 		field_end = strchr (scan, ' ');
132 		if (field_end != NULL) {
133 			fields[i] = g_strndup (scan, field_end - scan);
134 			scan = eat_spaces (field_end);
135 		}
136 	}
137 
138 	return fields;
139 }
140 
141 
142 static const char *
get_last_field_lha(char * line)143 get_last_field_lha (char *line)
144 {
145 	int         i;
146 	const char *field;
147 	int         n = 7;
148 
149 	if (strncmp (line, "[MS-DOS]", 8) == 0)
150 		n--;
151 
152 	if (strncmp (line, "[generic]", 9) == 0)
153 		n--;
154 
155 	if (strncmp (line, "[unknown]", 9) == 0)
156 		n--;
157 
158 	if (strncmp (line, "[Amiga]", 7) == 0)
159 		n--;
160 
161 	field = eat_spaces (line);
162 	for (i = 0; i < n; i++) {
163 		field = strchr (field, ' ');
164 		field = eat_spaces (field);
165 	}
166 
167 	return field;
168 }
169 
170 
171 static void
process_line(char * line,gpointer data)172 process_line (char     *line,
173 	      gpointer  data)
174 {
175 	FileData    *fdata;
176 	FrCommand   *comm = FR_COMMAND (data);
177 	char       **fields;
178 	const char  *name_field;
179 
180 	g_return_if_fail (line != NULL);
181 
182 	fdata = file_data_new ();
183 
184 	fields = split_line_lha (line);
185 	fdata->size = g_ascii_strtoull (fields[2], NULL, 10);
186 	fdata->modified = mktime_from_string (fields[4],
187 					      fields[5],
188 					      fields[6]);
189 	g_strfreev (fields);
190 
191 	/* Full path */
192 
193 	name_field = get_last_field_lha (line);
194 
195 	if (name_field && *name_field == '/') {
196 		fdata->full_path = g_strdup (name_field);
197 		fdata->original_path = fdata->full_path;
198 	} else {
199 		fdata->full_path = g_strconcat ("/", name_field, NULL);
200 		fdata->original_path = fdata->full_path + 1;
201 	}
202 
203 	fdata->link = NULL;
204 
205 	fdata->dir = line[0] == 'd';
206 	if (fdata->dir)
207 		fdata->name = dir_name_from_path (fdata->full_path);
208 	else
209 		fdata->name = g_strdup (file_name_from_path (fdata->full_path));
210 
211 	fdata->path = remove_level_from_path (fdata->full_path);
212 
213 	if (*fdata->name == 0)
214 		file_data_free (fdata);
215 	else
216 		fr_command_add_file (comm, fdata);
217 }
218 
219 
220 static void
fr_command_lha_list(FrCommand * comm)221 fr_command_lha_list (FrCommand  *comm)
222 {
223 	fr_process_set_out_line_func (comm->process, process_line, comm);
224 
225 	fr_process_begin_command (comm->process, "lha");
226 	fr_process_add_arg (comm->process, "lq");
227 	fr_process_add_arg (comm->process, comm->filename);
228 	fr_process_end_command (comm->process);
229 	fr_process_start (comm->process);
230 }
231 
232 
233 static void
fr_command_lha_add(FrCommand * comm,const char * from_file,GList * file_list,const char * base_dir,gboolean update,gboolean recursive)234 fr_command_lha_add (FrCommand     *comm,
235 		    const char    *from_file,
236 		    GList         *file_list,
237 		    const char    *base_dir,
238 		    gboolean       update,
239 		    gboolean       recursive)
240 {
241 	GList *scan;
242 
243 	fr_process_begin_command (comm->process, "lha");
244 	if (base_dir != NULL)
245 		fr_process_set_working_dir (comm->process, base_dir);
246 	if (update)
247 		fr_process_add_arg (comm->process, "u");
248 	else
249 		fr_process_add_arg (comm->process, "a");
250 	fr_process_add_arg (comm->process, comm->filename);
251 	for (scan = file_list; scan; scan = scan->next)
252 		fr_process_add_arg (comm->process, scan->data);
253 	fr_process_end_command (comm->process);
254 }
255 
256 
257 static void
fr_command_lha_delete(FrCommand * comm,const char * from_file,GList * file_list)258 fr_command_lha_delete (FrCommand  *comm,
259 		       const char *from_file,
260 		       GList      *file_list)
261 {
262 	GList *scan;
263 
264 	fr_process_begin_command (comm->process, "lha");
265 	fr_process_add_arg (comm->process, "d");
266 	fr_process_add_arg (comm->process, comm->filename);
267 	for (scan = file_list; scan; scan = scan->next)
268 		fr_process_add_arg (comm->process, scan->data);
269 	fr_process_end_command (comm->process);
270 }
271 
272 
273 static void
fr_command_lha_extract(FrCommand * comm,const char * from_file,GList * file_list,const char * dest_dir,gboolean overwrite,gboolean skip_older,gboolean junk_paths)274 fr_command_lha_extract (FrCommand  *comm,
275 			const char *from_file,
276 			GList      *file_list,
277 			const char *dest_dir,
278 			gboolean    overwrite,
279 			gboolean    skip_older,
280 			gboolean    junk_paths)
281 {
282 	GList *scan;
283 	char   options[5];
284 	int    i = 0;
285 
286 	fr_process_begin_command (comm->process, "lha");
287 
288 	if (dest_dir != NULL)
289 		fr_process_set_working_dir (comm->process, dest_dir);
290 
291 	options[i++] = 'x';
292 	options[i++] = 'f'; /* Always overwrite.
293 			     * The overwrite option is handled in
294 			     * fr_archive_extract,
295 			     * this is because lha asks the user whether he
296 			     * wants to overwrite a file. */
297 
298 	if (junk_paths)
299 		options[i++] = 'i';
300 
301 	options[i++] = 0;
302 	fr_process_add_arg (comm->process, options);
303 	fr_process_add_arg (comm->process, comm->filename);
304 
305 	for (scan = file_list; scan; scan = scan->next)
306 		fr_process_add_arg (comm->process, scan->data);
307 
308 	fr_process_end_command (comm->process);
309 }
310 
311 
312 const char *lha_mime_type[] = { "application/x-lha", NULL };
313 
314 
315 static const char **
fr_command_lha_get_mime_types(FrCommand * comm)316 fr_command_lha_get_mime_types (FrCommand *comm)
317 {
318 	return lha_mime_type;
319 }
320 
321 
322 static FrCommandCap
fr_command_lha_get_capabilities(FrCommand * comm,const char * mime_type,gboolean check_command)323 fr_command_lha_get_capabilities (FrCommand  *comm,
324 			         const char *mime_type,
325 				 gboolean    check_command)
326 {
327 	FrCommandCap capabilities;
328 
329 	capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES;
330 	if (is_program_available ("lha", check_command))
331 		capabilities |= FR_COMMAND_CAN_READ_WRITE;
332 
333 	return capabilities;
334 }
335 
336 
337 static const char *
fr_command_lha_get_packages(FrCommand * comm,const char * mime_type)338 fr_command_lha_get_packages (FrCommand  *comm,
339 			     const char *mime_type)
340 {
341 	return PACKAGES ("lha");
342 }
343 
344 
345 static void
fr_command_lha_class_init(FrCommandLhaClass * class)346 fr_command_lha_class_init (FrCommandLhaClass *class)
347 {
348         GObjectClass   *gobject_class = G_OBJECT_CLASS (class);
349         FrCommandClass *afc;
350 
351         parent_class = g_type_class_peek_parent (class);
352 	afc = (FrCommandClass*) class;
353 
354 	gobject_class->finalize = fr_command_lha_finalize;
355 
356         afc->list             = fr_command_lha_list;
357 	afc->add              = fr_command_lha_add;
358 	afc->delete_           = fr_command_lha_delete;
359 	afc->extract          = fr_command_lha_extract;
360 	afc->get_mime_types   = fr_command_lha_get_mime_types;
361 	afc->get_capabilities = fr_command_lha_get_capabilities;
362 	afc->get_packages     = fr_command_lha_get_packages;
363 }
364 
365 
366 static void
fr_command_lha_init(FrCommand * comm)367 fr_command_lha_init (FrCommand *comm)
368 {
369 	comm->propAddCanUpdate             = TRUE;
370 	comm->propAddCanReplace            = TRUE;
371 	comm->propAddCanStoreFolders       = TRUE;
372 	comm->propExtractCanAvoidOverwrite = FALSE;
373 	comm->propExtractCanSkipOlder      = FALSE;
374 	comm->propExtractCanJunkPaths      = TRUE;
375 	comm->propPassword                 = FALSE;
376 	comm->propTest                     = FALSE;
377 }
378 
379 
380 static void
fr_command_lha_finalize(GObject * object)381 fr_command_lha_finalize (GObject *object)
382 {
383         g_return_if_fail (object != NULL);
384         g_return_if_fail (FR_IS_COMMAND_LHA (object));
385 
386 	 /* Chain up */
387         if (G_OBJECT_CLASS (parent_class)->finalize)
388 		G_OBJECT_CLASS (parent_class)->finalize (object);
389 }
390 
391 
392 GType
fr_command_lha_get_type()393 fr_command_lha_get_type ()
394 {
395         static GType type = 0;
396 
397         if (! type) {
398                 GTypeInfo type_info = {
399 			sizeof (FrCommandLhaClass),
400 			NULL,
401 			NULL,
402 			(GClassInitFunc) fr_command_lha_class_init,
403 			NULL,
404 			NULL,
405 			sizeof (FrCommandLha),
406 			0,
407 			(GInstanceInitFunc) fr_command_lha_init
408 		};
409 
410 		type = g_type_register_static (FR_TYPE_COMMAND,
411 					       "FRCommandLha",
412 					       &type_info,
413 					       0);
414         }
415 
416         return type;
417 }
418