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