1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * Engrampa
5 *
6 * Copyright (C) 2001, 2003 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-arj.h"
34
35 static void fr_command_arj_class_init (FrCommandArjClass *class);
36 static void fr_command_arj_init (FrCommand *afile);
37 static void fr_command_arj_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 * date_s,char * time_s)47 mktime_from_string (char *date_s,
48 char *time_s)
49 {
50 struct tm tm = {0, };
51 char **fields;
52
53 tm.tm_isdst = -1;
54
55 /* date */
56
57 fields = g_strsplit (date_s, "-", 3);
58 if (fields[0] != NULL) {
59 /* warning : this will work until 2075 ;) */
60 int y = atoi (fields[0]);
61 if (y >= 75)
62 tm.tm_year = y;
63 else
64 tm.tm_year = 100 + y;
65
66 tm.tm_mon = atoi (fields[1]) - 1;
67 tm.tm_mday = atoi (fields[2]);
68 }
69 g_strfreev (fields);
70
71 /* time */
72
73 fields = g_strsplit (time_s, ":", 3);
74 if (fields[0] != NULL) {
75 tm.tm_hour = atoi (fields[0]);
76 if (fields[1] != NULL) {
77 tm.tm_min = atoi (fields[1]);
78 if (fields[2] != NULL)
79 tm.tm_sec = atoi (fields[2]);
80 }
81 }
82 g_strfreev (fields);
83
84 return mktime (&tm);
85 }
86
87
88 static void
list__process_line(char * line,gpointer data)89 list__process_line (char *line,
90 gpointer data)
91 {
92 FrCommand *comm = FR_COMMAND (data);
93 FrCommandArj *arj_comm = FR_COMMAND_ARJ (comm);
94
95 g_return_if_fail (line != NULL);
96
97 if (! arj_comm->list_started) {
98 if (strncmp (line, "--------", 8) == 0) {
99 arj_comm->list_started = TRUE;
100 arj_comm->line_no = 1;
101 }
102 return;
103 }
104
105 if (strncmp (line, "--------", 8) == 0) {
106 arj_comm->list_started = FALSE;
107 return;
108 }
109
110 if (g_regex_match (arj_comm->filename_line_regex, line, 0, NULL)) { /* Read the filename. */
111 FileData *fdata;
112 const char *name_field;
113
114 arj_comm->line_no = 1;
115
116 arj_comm->fdata = fdata = file_data_new ();
117
118 name_field = get_last_field (line, 2);
119
120 if (*name_field == '/') {
121 fdata->full_path = g_strdup (name_field);
122 fdata->original_path = fdata->full_path;
123 }
124 else {
125 fdata->full_path = g_strconcat ("/", name_field, NULL);
126 fdata->original_path = fdata->full_path + 1;
127 }
128
129 fdata->link = NULL;
130
131 fdata->name = g_strdup (file_name_from_path (fdata->full_path));
132 fdata->path = remove_level_from_path (fdata->full_path);
133 }
134 else if (arj_comm->line_no == 2) { /* Read file size and date. */
135 FileData *fdata;
136 char **fields;
137
138 fdata = arj_comm->fdata;
139
140 /* read file info. */
141
142 fields = split_line (line, 10);
143 fdata->size = g_ascii_strtoull (fields[2], NULL, 10);
144 fdata->modified = mktime_from_string (fields[5], fields[6]);
145 if ((strcmp (fields[1], "MS-DOS") == 0) || (strcmp (fields[1], "WIN32") == 0))
146 fdata->encrypted = (g_ascii_strcasecmp (fields[7], "11") == 0);
147 else
148 fdata->encrypted = (g_ascii_strcasecmp (fields[9], "11") == 0);
149 g_strfreev (fields);
150
151 if (*fdata->name == 0)
152 file_data_free (fdata);
153 else
154 fr_command_add_file (comm, fdata);
155 arj_comm->fdata = NULL;
156 }
157
158 arj_comm->line_no++;
159 }
160
161
162 static void
fr_command_arj_list(FrCommand * comm)163 fr_command_arj_list (FrCommand *comm)
164 {
165 fr_process_set_out_line_func (comm->process, list__process_line, comm);
166
167 fr_process_begin_command (comm->process, "arj");
168 fr_process_add_arg (comm->process, "v");
169 fr_process_add_arg (comm->process, "-y");
170 fr_process_add_arg (comm->process, "-");
171 fr_process_add_arg (comm->process, comm->filename);
172 fr_process_end_command (comm->process);
173 fr_process_start (comm->process);
174 }
175
176
177 static void
fr_command_arj_add(FrCommand * comm,const char * from_file,GList * file_list,const char * base_dir,gboolean update,gboolean recursive)178 fr_command_arj_add (FrCommand *comm,
179 const char *from_file,
180 GList *file_list,
181 const char *base_dir,
182 gboolean update,
183 gboolean recursive)
184 {
185 GList *scan;
186
187 fr_process_begin_command (comm->process, "arj");
188
189 fr_process_add_arg (comm->process, "a");
190
191 if (base_dir != NULL)
192 fr_process_set_working_dir (comm->process, base_dir);
193
194 if (update)
195 fr_process_add_arg (comm->process, "-u");
196
197 if (comm->password != NULL)
198 fr_process_add_arg_concat (comm->process, "-g/", comm->password, NULL);
199
200 switch (comm->compression) {
201 case FR_COMPRESSION_VERY_FAST:
202 fr_process_add_arg (comm->process, "-m3"); break;
203 case FR_COMPRESSION_FAST:
204 fr_process_add_arg (comm->process, "-m2"); break;
205 case FR_COMPRESSION_NORMAL:
206 fr_process_add_arg (comm->process, "-m1"); break;
207 case FR_COMPRESSION_MAXIMUM:
208 fr_process_add_arg (comm->process, "-m1"); break;
209 }
210
211 fr_process_add_arg (comm->process, "-i");
212 fr_process_add_arg (comm->process, "-y");
213 fr_process_add_arg (comm->process, "-");
214
215 fr_process_add_arg (comm->process, comm->filename);
216
217 for (scan = file_list; scan; scan = scan->next)
218 fr_process_add_arg (comm->process, (gchar*) scan->data);
219
220 fr_process_end_command (comm->process);
221 }
222
223
224 static void
fr_command_arj_delete(FrCommand * comm,const char * from_file,GList * file_list)225 fr_command_arj_delete (FrCommand *comm,
226 const char *from_file,
227 GList *file_list)
228 {
229 GList *scan;
230
231 fr_process_begin_command (comm->process, "arj");
232 fr_process_add_arg (comm->process, "d");
233
234 fr_process_add_arg (comm->process, "-i");
235 fr_process_add_arg (comm->process, "-y");
236 fr_process_add_arg (comm->process, "-");
237
238 fr_process_add_arg (comm->process, comm->filename);
239
240 for (scan = file_list; scan; scan = scan->next)
241 fr_process_add_arg (comm->process, scan->data);
242 fr_process_end_command (comm->process);
243 }
244
245
246 static void
fr_command_arj_extract(FrCommand * comm,const char * from_file,GList * file_list,const char * dest_dir,gboolean overwrite,gboolean skip_older,gboolean junk_paths)247 fr_command_arj_extract (FrCommand *comm,
248 const char *from_file,
249 GList *file_list,
250 const char *dest_dir,
251 gboolean overwrite,
252 gboolean skip_older,
253 gboolean junk_paths)
254 {
255 GList *scan;
256
257 fr_process_begin_command (comm->process, "arj");
258
259 if (junk_paths)
260 fr_process_add_arg (comm->process, "e");
261 else
262 fr_process_add_arg (comm->process, "x");
263
264 if (dest_dir != NULL)
265 fr_process_add_arg_concat (comm->process, "-ht/", dest_dir, NULL);
266
267 if (! overwrite)
268 fr_process_add_arg (comm->process, "-n");
269
270 if (skip_older)
271 fr_process_add_arg (comm->process, "-u");
272
273 if (comm->password != NULL)
274 fr_process_add_arg_concat (comm->process, "-g/", comm->password, NULL);
275 else
276 fr_process_add_arg (comm->process, "-g/");
277
278 fr_process_add_arg (comm->process, "-i");
279 fr_process_add_arg (comm->process, "-y");
280 fr_process_add_arg (comm->process, "-");
281
282 fr_process_add_arg (comm->process, comm->filename);
283
284 for (scan = file_list; scan; scan = scan->next)
285 fr_process_add_arg (comm->process, scan->data);
286
287 fr_process_end_command (comm->process);
288 }
289
290
291 static void
fr_command_arj_test(FrCommand * comm)292 fr_command_arj_test (FrCommand *comm)
293 {
294 fr_process_begin_command (comm->process, "arj");
295 fr_process_add_arg (comm->process, "t");
296 if (comm->password != NULL)
297 fr_process_add_arg_concat (comm->process, "-g/", comm->password, NULL);
298 fr_process_add_arg (comm->process, "-i");
299 fr_process_add_arg (comm->process, "-y");
300 fr_process_add_arg (comm->process, "-");
301 fr_process_add_arg (comm->process, comm->filename);
302 fr_process_end_command (comm->process);
303 }
304
305
306 static void
fr_command_arj_handle_error(FrCommand * comm,FrProcError * error)307 fr_command_arj_handle_error (FrCommand *comm,
308 FrProcError *error)
309 {
310 if (error->type != FR_PROC_ERROR_NONE) {
311 if (error->status <= 1)
312 error->type = FR_PROC_ERROR_NONE;
313 else if (error->status == 3)
314 error->type = FR_PROC_ERROR_ASK_PASSWORD;
315 }
316 }
317
318
319 const char *arj_mime_type[] = { "application/x-arj", NULL };
320
321
322 static const char **
fr_command_arj_get_mime_types(FrCommand * comm)323 fr_command_arj_get_mime_types (FrCommand *comm)
324 {
325 return arj_mime_type;
326 }
327
328
329 static FrCommandCap
fr_command_arj_get_capabilities(FrCommand * comm,const char * mime_type,gboolean check_command)330 fr_command_arj_get_capabilities (FrCommand *comm,
331 const char *mime_type,
332 gboolean check_command)
333 {
334 FrCommandCap capabilities;
335
336 capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES | FR_COMMAND_CAN_ENCRYPT;
337 if (is_program_available ("arj", check_command))
338 capabilities |= FR_COMMAND_CAN_READ_WRITE;
339
340 return capabilities;
341 }
342
343
344 static const char *
fr_command_arj_get_packages(FrCommand * comm,const char * mime_type)345 fr_command_arj_get_packages (FrCommand *comm,
346 const char *mime_type)
347 {
348 return PACKAGES ("arj");
349 }
350
351
352 static void
fr_command_arj_class_init(FrCommandArjClass * class)353 fr_command_arj_class_init (FrCommandArjClass *class)
354 {
355 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
356 FrCommandClass *afc;
357
358 parent_class = g_type_class_peek_parent (class);
359 afc = (FrCommandClass*) class;
360
361 gobject_class->finalize = fr_command_arj_finalize;
362
363 afc->list = fr_command_arj_list;
364 afc->add = fr_command_arj_add;
365 afc->delete_ = fr_command_arj_delete;
366 afc->extract = fr_command_arj_extract;
367 afc->test = fr_command_arj_test;
368 afc->handle_error = fr_command_arj_handle_error;
369 afc->get_mime_types = fr_command_arj_get_mime_types;
370 afc->get_capabilities = fr_command_arj_get_capabilities;
371 afc->get_packages = fr_command_arj_get_packages;
372 }
373
374
375 static void
fr_command_arj_init(FrCommand * comm)376 fr_command_arj_init (FrCommand *comm)
377 {
378 FrCommandArj *arj_comm;
379
380 comm->propAddCanUpdate = TRUE;
381 comm->propAddCanReplace = TRUE;
382 comm->propAddCanStoreFolders = FALSE;
383 comm->propExtractCanAvoidOverwrite = TRUE;
384 comm->propExtractCanSkipOlder = TRUE;
385 comm->propExtractCanJunkPaths = TRUE;
386 comm->propPassword = TRUE;
387 comm->propTest = TRUE;
388
389 arj_comm = FR_COMMAND_ARJ (comm);
390 arj_comm->list_started = FALSE;
391 arj_comm->fdata = FALSE;
392 arj_comm->filename_line_regex = g_regex_new ("[0-9]+\\) ", G_REGEX_OPTIMIZE, 0, NULL);
393 }
394
395
396 static void
fr_command_arj_finalize(GObject * object)397 fr_command_arj_finalize (GObject *object)
398 {
399 FrCommandArj *arj_comm;
400
401 g_return_if_fail (object != NULL);
402 g_return_if_fail (FR_IS_COMMAND_ARJ (object));
403
404 arj_comm = FR_COMMAND_ARJ (object);
405 g_regex_unref (arj_comm->filename_line_regex);
406
407 /* Chain up */
408 if (G_OBJECT_CLASS (parent_class)->finalize)
409 G_OBJECT_CLASS (parent_class)->finalize (object);
410 }
411
412
413 GType
fr_command_arj_get_type()414 fr_command_arj_get_type ()
415 {
416 static GType type = 0;
417
418 if (! type) {
419 GTypeInfo type_info = {
420 sizeof (FrCommandArjClass),
421 NULL,
422 NULL,
423 (GClassInitFunc) fr_command_arj_class_init,
424 NULL,
425 NULL,
426 sizeof (FrCommandArj),
427 0,
428 (GInstanceInitFunc) fr_command_arj_init
429 };
430
431 type = g_type_register_static (FR_TYPE_COMMAND,
432 "FRCommandArj",
433 &type_info,
434 0);
435 }
436
437 return type;
438 }
439