1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * File-Roller
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, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27 #include <glib.h>
28 #include <glib/gi18n.h>
29 #include "file-data.h"
30 #include "file-utils.h"
31 #include "gio-utils.h"
32 #include "glib-utils.h"
33 #include "fr-command.h"
34 #include "fr-command-rar.h"
35 #include "fr-error.h"
36 #include "rar-utils.h"
37
38
39 struct _FrCommandRar
40 {
41 FrCommand parent_instance;
42
43 gboolean list_started;
44 gboolean rar4_odd_line;
45 gboolean rar5;
46 gboolean rar5_30;
47 FileData *fdata;
48 };
49
50
G_DEFINE_TYPE(FrCommandRar,fr_command_rar,fr_command_get_type ())51 G_DEFINE_TYPE (FrCommandRar, fr_command_rar, fr_command_get_type ())
52
53
54 static gboolean
55 have_rar (void)
56 {
57 return _g_program_is_in_path ("rar");
58 }
59
60
61 /* -- list -- */
62
63
64 static time_t
mktime_from_string(const char * date_s,const char * time_s)65 mktime_from_string (const char *date_s,
66 const char *time_s)
67 {
68 struct tm tm = {0, };
69 char **fields;
70
71 tm.tm_isdst = -1;
72
73 /* date */
74
75 fields = g_strsplit (date_s, "-", 3);
76 if (fields[0] != NULL) {
77 tm.tm_mday = atoi (fields[0]);
78 if (fields[1] != NULL) {
79 tm.tm_mon = atoi (fields[1]) - 1;
80 if (fields[2] != NULL)
81 tm.tm_year = 100 + atoi (fields[2]);
82 }
83 }
84 g_strfreev (fields);
85
86 /* time */
87
88 fields = g_strsplit (time_s, ":", 2);
89 if (fields[0] != NULL) {
90 tm.tm_hour = atoi (fields[0]);
91 if (fields[1] != NULL)
92 tm.tm_min = atoi (fields[1]);
93 }
94 g_strfreev (fields);
95
96 return mktime (&tm);
97 }
98
99
100 static time_t
mktime_from_string_rar_5_30(const char * date_s,const char * time_s)101 mktime_from_string_rar_5_30 (const char *date_s,
102 const char *time_s)
103 {
104 struct tm tm = {0, };
105 char **fields;
106
107 tm.tm_isdst = -1;
108
109 /* date */
110
111 fields = g_strsplit (date_s, "-", 3);
112 if (fields[0] != NULL) {
113 tm.tm_year = atoi (fields[0]) - 1900;
114 if (fields[1] != NULL) {
115 tm.tm_mon = atoi (fields[1]) - 1;
116 if (fields[2] != NULL)
117 tm.tm_mday = atoi (fields[2]);
118 }
119 }
120 g_strfreev (fields);
121
122 /* time */
123
124 fields = g_strsplit (time_s, ":", 2);
125 if (fields[0] != NULL) {
126 tm.tm_hour = atoi (fields[0]);
127 if (fields[1] != NULL)
128 tm.tm_min = atoi (fields[1]);
129 }
130 g_strfreev (fields);
131
132 return mktime (&tm);
133 }
134
135
136 /*
137 * Sample rar 5.30 or higher output:
138 *
139
140 RAR 5.30 Copyright (c) 1993-2017 Alexander Roshal 11 Aug 2017
141 Trial version Type 'rar -?' for help
142
143 Archive: test.rar
144 Details: RAR 5
145
146 Attributes Size Packed Ratio Date Time Checksum Name
147 ----------- --------- -------- ----- ---------- ----- -------- ----
148 -rw-r--r-- 51 47 92% 2017-11-19 16:20 80179DAB loremipsum.txt
149 ----------- --------- -------- ----- ---------- ----- -------- ----
150 51 47 92% 1
151
152 */
153
154 /* Sample rar-5 listing output:
155
156 RAR 5.00 beta 8 Copyright (c) 1993-2013 Alexander Roshal 22 Aug 2013
157 Trial version Type RAR -? for help
158
159 Archive: test.rar
160 Details: RAR 4
161
162 Attributes Size Packed Ratio Date Time Checksum Name
163 ----------- --------- -------- ----- -------- ----- -------- ----
164 -rw-r--r-- 453 304 67% 05-09-13 09:55 56DA5EF3 loremipsum.txt
165 ----------- --------- -------- ----- -------- ----- -------- ----
166 453 304 67% 1
167
168 *
169 * Sample rar-4 listing output:
170 *
171
172 RAR 4.20 Copyright (c) 1993-2012 Alexander Roshal 9 Jun 2012
173 Trial version Type RAR -? for help
174
175 Archive test.rar
176
177 Pathname/Comment
178 Size Packed Ratio Date Time Attr CRC Meth Ver
179 -------------------------------------------------------------------------------
180 loremipsum.txt
181 453 304 67% 05-09-13 09:55 -rw-r--r-- 56DA5EF3 m3b 2.9
182 -------------------------------------------------------------------------------
183 1 453 304 67%
184
185 */
186
187 static gboolean
attribute_field_with_space(char * line)188 attribute_field_with_space (char *line)
189 {
190 /* sometimes when the archive is encrypted the attributes field is
191 * like this: "* ..A...."
192 * */
193 return ((line[0] != ' ') && (line[1] == ' '));
194 }
195
196
197 static void
parse_name_field(char * line,FrCommandRar * rar_comm)198 parse_name_field (char *line,
199 FrCommandRar *rar_comm)
200 {
201 char *name_field;
202 FileData *fdata;
203
204 rar_comm->fdata = fdata = file_data_new ();
205
206 /* read file name. */
207
208 fdata->encrypted = (line[0] == '*') ? TRUE : FALSE;
209
210 if (rar_comm->rar5)
211 /* rar-5 output adds trailing spaces to short file names :( */
212 name_field = g_strchomp (g_strdup (_g_str_get_last_field (line, attribute_field_with_space (line) ? 9 : 8)));
213 else
214 name_field = g_strdup (line + 1);
215
216 if (name_field == NULL)
217 return;
218
219 if (*name_field == '/') {
220 fdata->full_path = g_strdup (name_field);
221 fdata->original_path = fdata->full_path;
222 }
223 else {
224 fdata->full_path = g_strconcat ("/", name_field, NULL);
225 fdata->original_path = fdata->full_path + 1;
226 }
227
228 fdata->link = NULL;
229 fdata->path = _g_path_remove_level (fdata->full_path);
230
231 g_free (name_field);
232 }
233
234 static gboolean
attr_field_is_dir(const char * attr_field,FrCommandRar * rar_comm)235 attr_field_is_dir (const char *attr_field,
236 FrCommandRar *rar_comm)
237 {
238 if ((attr_field[0] == 'd') ||
239 (rar_comm->rar5 && attr_field[3] == 'D') ||
240 (!rar_comm->rar5 && attr_field[1] == 'D'))
241 return TRUE;
242
243 return FALSE;
244 }
245
246 static void
process_line(char * line,gpointer data)247 process_line (char *line,
248 gpointer data)
249 {
250 FrCommand *comm = FR_COMMAND (data);
251 FrCommandRar *rar_comm = FR_COMMAND_RAR (comm);
252 char **fields;
253
254 g_return_if_fail (line != NULL);
255
256 if (! rar_comm->list_started) {
257 if ((strncmp (line, "RAR ", 4) == 0) || (strncmp (line, "UNRAR ", 6) == 0)) {
258 int major_version;
259 int minor_version;
260
261 if (strncmp (line, "RAR ", 4) == 0)
262 sscanf (line, "RAR %d.%d", &major_version, &minor_version);
263 else
264 sscanf (line, "UNRAR %d.%d", &major_version, &minor_version);
265
266 rar_comm->rar5 = (major_version >= 5);
267 rar_comm->rar5_30 = ((major_version == 5) && (minor_version >= 30)) || (major_version >= 6);
268 }
269 else if (strncmp (line, "--------", 8) == 0) {
270 rar_comm->list_started = TRUE;
271 if (! rar_comm->rar5)
272 rar_comm->rar4_odd_line = TRUE;
273 }
274 else if (strncmp (line, "Volume ", 7) == 0)
275 FR_ARCHIVE (comm)->multi_volume = TRUE;
276 return;
277 }
278
279 if (strncmp (line, "--------", 8) == 0) {
280 rar_comm->list_started = FALSE;
281 return;
282 }
283
284 if (rar_comm->rar4_odd_line || rar_comm->rar5)
285 parse_name_field (line, rar_comm);
286
287 if (! rar_comm->rar4_odd_line) {
288 FileData *fdata;
289 const char *size_field, *ratio_field, *date_field, *time_field, *attr_field;
290
291 fdata = rar_comm->fdata;
292
293 /* read file info. */
294
295 fields = _g_str_split_line (line, attribute_field_with_space (line) ? 7 : 6);
296 if (rar_comm->rar5) {
297 int offset = attribute_field_with_space (line) ? 1 : 0;
298
299 size_field = fields[1+offset];
300 ratio_field = fields[3+offset];
301 date_field = fields[4+offset];
302 time_field = fields[5+offset];
303 attr_field = fields[0+offset];
304 }
305 else {
306 size_field = fields[0];
307 ratio_field = fields[2];
308 date_field = fields[3];
309 time_field = fields[4];
310 attr_field = fields[5];
311 }
312 if (g_strv_length (fields) < 6) {
313 /* wrong line format, treat this line as a filename line */
314 g_strfreev (fields);
315 file_data_free (rar_comm->fdata);
316 rar_comm->fdata = NULL;
317 rar_comm->rar4_odd_line = TRUE;
318 parse_name_field (line, rar_comm);
319 }
320 else {
321 if ((strcmp (ratio_field, "<->") == 0)
322 || (strcmp (ratio_field, "<--") == 0))
323 {
324 /* ignore files that span more volumes */
325
326 file_data_free (rar_comm->fdata);
327 rar_comm->fdata = NULL;
328 }
329 else {
330 fdata->size = g_ascii_strtoull (size_field, NULL, 10);
331
332 fdata->modified = rar_comm->rar5_30 ? mktime_from_string_rar_5_30 (date_field, time_field) : mktime_from_string (date_field, time_field);
333
334 if (attr_field_is_dir (attr_field, rar_comm)) {
335 char *tmp;
336
337 tmp = fdata->full_path;
338 fdata->full_path = g_strconcat (fdata->full_path, "/", NULL);
339
340 fdata->original_path = g_strdup (fdata->original_path);
341 fdata->free_original_path = TRUE;
342
343 g_free (tmp);
344
345 fdata->name = _g_path_get_dir_name (fdata->full_path);
346 fdata->dir = TRUE;
347 }
348 else {
349 fdata->name = g_strdup (_g_path_get_basename (fdata->full_path));
350 if (attr_field[0] == 'l')
351 fdata->link = g_strdup (_g_path_get_basename (fdata->full_path));
352 }
353
354 fr_archive_add_file (FR_ARCHIVE (comm), fdata);
355 rar_comm->fdata = NULL;
356 }
357
358 g_strfreev (fields);
359 }
360 }
361
362 if (! rar_comm->rar5)
363 rar_comm->rar4_odd_line = ! rar_comm->rar4_odd_line;
364 }
365
366
367 static void
add_password_arg(FrCommand * comm,const char * password,gboolean disable_query)368 add_password_arg (FrCommand *comm,
369 const char *password,
370 gboolean disable_query)
371 {
372 if ((password != NULL) && (password[0] != '\0')) {
373 if (FR_ARCHIVE (comm)->encrypt_header)
374 fr_process_add_arg_concat (comm->process, "-hp", password, NULL);
375 else
376 fr_process_add_arg_concat (comm->process, "-p", password, NULL);
377 }
378 else if (disable_query)
379 fr_process_add_arg (comm->process, "-p-");
380 }
381
382
383 static void
list__begin(gpointer data)384 list__begin (gpointer data)
385 {
386 FrCommandRar *comm = data;
387
388 comm->list_started = FALSE;
389 }
390
391
392 static gboolean
fr_command_rar_list(FrCommand * comm)393 fr_command_rar_list (FrCommand *comm)
394 {
395 rar_check_multi_volume (comm);
396
397 fr_process_set_out_line_func (comm->process, process_line, comm);
398
399 if (have_rar ())
400 fr_process_begin_command (comm->process, "rar");
401 else
402 fr_process_begin_command (comm->process, "unrar");
403 fr_process_set_begin_func (comm->process, list__begin, comm);
404 fr_process_add_arg (comm->process, "v");
405 fr_process_add_arg (comm->process, "-c-");
406 fr_process_add_arg (comm->process, "-v");
407
408 add_password_arg (comm, FR_ARCHIVE (comm)->password, TRUE);
409
410 /* stop switches scanning */
411 fr_process_add_arg (comm->process, "--");
412
413 fr_process_add_arg (comm->process, comm->filename);
414 fr_process_end_command (comm->process);
415
416 return TRUE;
417 }
418
419
420 static void
parse_progress_line(FrCommand * comm,const char * prefix,const char * message_format,const char * line)421 parse_progress_line (FrCommand *comm,
422 const char *prefix,
423 const char *message_format,
424 const char *line)
425 {
426 FrArchive *archive = FR_ARCHIVE (comm);
427 int prefix_len;
428
429 prefix_len = strlen (prefix);
430 if (strncmp (line, prefix, prefix_len) == 0) {
431 if (fr_archive_progress_get_total_files (archive) > 0) {
432 fr_archive_progress (archive, fr_archive_progress_inc_completed_files (archive, 1));
433 }
434 else {
435 char filename[4096];
436 char *b_idx;
437 int len;
438 char *msg;
439
440 strcpy (filename, line + prefix_len);
441
442 /* when a new volume is created a sequence of backspaces is
443 * issued, remove the backspaces from the filename */
444 b_idx = strchr (filename, '\x08');
445 if (b_idx != NULL)
446 *b_idx = 0;
447
448 /* remove the OK at the end of the filename */
449 len = strlen (filename);
450 if ((len > 5) && (strncmp (filename + len - 5, " OK ", 5) == 0))
451 filename[len - 5] = 0;
452
453 msg = g_strdup_printf (message_format, _g_path_get_basename (filename), NULL);
454 fr_archive_message (archive, msg);
455
456 g_free (msg);
457 }
458 }
459 }
460
461
462 static void
process_line__add(char * line,gpointer data)463 process_line__add (char *line,
464 gpointer data)
465 {
466 FrCommand *comm = FR_COMMAND (data);
467 FrArchive *archive = FR_ARCHIVE (comm);
468
469 if (strncmp (line, "Creating archive ", 17) == 0) {
470 const char *archive_filename = line + 17;
471 char *uri;
472
473 uri = g_filename_to_uri (archive_filename, NULL, NULL);
474 if ((archive->volume_size > 0)
475 && g_regex_match_simple ("^.*\\.part(0)*2\\.rar$", uri, G_REGEX_CASELESS, 0))
476 {
477 char *volume_filename;
478 GFile *volume_file;
479
480 volume_filename = g_strdup (archive_filename);
481 volume_filename[strlen (volume_filename) - 5] = '1';
482 volume_file = g_file_new_for_path (volume_filename);
483 fr_archive_set_multi_volume (archive, volume_file);
484
485 g_object_unref (volume_file);
486 g_free (volume_filename);
487 }
488 fr_archive_working_archive (archive, uri);
489
490 g_free (uri);
491 return;
492 }
493
494 if (fr_archive_progress_get_total_files (archive) > 0)
495 parse_progress_line (comm, "Adding ", _("Adding “%s”"), line);
496 }
497
498
499 static void
fr_command_rar_add(FrCommand * comm,const char * from_file,GList * file_list,const char * base_dir,gboolean update,gboolean follow_links)500 fr_command_rar_add (FrCommand *comm,
501 const char *from_file,
502 GList *file_list,
503 const char *base_dir,
504 gboolean update,
505 gboolean follow_links)
506 {
507 GList *scan;
508
509 fr_process_use_standard_locale (comm->process, TRUE);
510 fr_process_set_out_line_func (comm->process,
511 process_line__add,
512 comm);
513
514 fr_process_begin_command (comm->process, "rar");
515
516 if (base_dir != NULL)
517 fr_process_set_working_dir (comm->process, base_dir);
518
519 if (update)
520 fr_process_add_arg (comm->process, "u");
521 else
522 fr_process_add_arg (comm->process, "a");
523
524 if (! follow_links)
525 fr_process_add_arg (comm->process, "-ol");
526
527 switch (FR_ARCHIVE (comm)->compression) {
528 case FR_COMPRESSION_VERY_FAST:
529 fr_process_add_arg (comm->process, "-m1"); break;
530 case FR_COMPRESSION_FAST:
531 fr_process_add_arg (comm->process, "-m2"); break;
532 case FR_COMPRESSION_NORMAL:
533 fr_process_add_arg (comm->process, "-m3"); break;
534 case FR_COMPRESSION_MAXIMUM:
535 fr_process_add_arg (comm->process, "-m5"); break;
536 }
537
538 add_password_arg (comm, FR_ARCHIVE (comm)->password, FALSE);
539
540 if (FR_ARCHIVE (comm)->volume_size > 0)
541 fr_process_add_arg_printf (comm->process, "-v%ub", FR_ARCHIVE (comm)->volume_size);
542
543 /* disable percentage indicator */
544 fr_process_add_arg (comm->process, "-Idp");
545
546 fr_process_add_arg (comm->process, "--");
547 fr_process_add_arg (comm->process, comm->filename);
548
549 if (from_file == NULL)
550 for (scan = file_list; scan; scan = scan->next)
551 fr_process_add_arg (comm->process, scan->data);
552 else
553 fr_process_add_arg_concat (comm->process, "@", from_file, NULL);
554
555 fr_process_end_command (comm->process);
556 }
557
558
559 static void
process_line__delete(char * line,gpointer data)560 process_line__delete (char *line,
561 gpointer data)
562 {
563 FrCommand *comm = FR_COMMAND (data);
564
565 if (strncmp (line, "Deleting from ", 14) == 0) {
566 char *uri;
567
568 uri = g_filename_to_uri (line + 14, NULL, NULL);
569 fr_archive_working_archive (FR_ARCHIVE (comm), uri);
570 g_free (uri);
571
572 return;
573 }
574
575 if (fr_archive_progress_get_total_files (FR_ARCHIVE (comm)) > 0)
576 parse_progress_line (comm, "Deleting ", _("Removing “%s”"), line);
577 }
578
579
580 static void
fr_command_rar_delete(FrCommand * comm,const char * from_file,GList * file_list)581 fr_command_rar_delete (FrCommand *comm,
582 const char *from_file,
583 GList *file_list)
584 {
585 GList *scan;
586
587 fr_process_use_standard_locale (comm->process, TRUE);
588 fr_process_set_out_line_func (comm->process,
589 process_line__delete,
590 comm);
591
592 fr_process_begin_command (comm->process, "rar");
593 fr_process_add_arg (comm->process, "d");
594
595 add_password_arg (comm, FR_ARCHIVE (comm)->password, FALSE);
596
597 fr_process_add_arg (comm->process, "--");
598 fr_process_add_arg (comm->process, comm->filename);
599
600 if (from_file == NULL)
601 for (scan = file_list; scan; scan = scan->next)
602 fr_process_add_arg (comm->process, scan->data);
603 else
604 fr_process_add_arg_concat (comm->process, "@", from_file, NULL);
605
606 fr_process_end_command (comm->process);
607 }
608
609
610 static void
process_line__extract(char * line,gpointer data)611 process_line__extract (char *line,
612 gpointer data)
613 {
614 FrCommand *comm = FR_COMMAND (data);
615
616 if (strncmp (line, "Extracting from ", 16) == 0) {
617 char *uri;
618
619 uri = g_filename_to_uri (line + 16, NULL, NULL);
620 fr_archive_working_archive (FR_ARCHIVE (comm), uri);
621 g_free (uri);
622
623 return;
624 }
625
626 if (fr_archive_progress_get_total_files (FR_ARCHIVE (comm)) > 0)
627 parse_progress_line (comm, "Extracting ", _("Extracting “%s”"), line);
628 }
629
630
631 static void
fr_command_rar_extract(FrCommand * comm,const char * from_file,GList * file_list,const char * dest_dir,gboolean overwrite,gboolean skip_older,gboolean junk_paths)632 fr_command_rar_extract (FrCommand *comm,
633 const char *from_file,
634 GList *file_list,
635 const char *dest_dir,
636 gboolean overwrite,
637 gboolean skip_older,
638 gboolean junk_paths)
639 {
640 GList *scan;
641
642 fr_process_use_standard_locale (comm->process, TRUE);
643 fr_process_set_out_line_func (comm->process,
644 process_line__extract,
645 comm);
646
647 if (have_rar ())
648 fr_process_begin_command (comm->process, "rar");
649 else
650 fr_process_begin_command (comm->process, "unrar");
651
652 fr_process_add_arg (comm->process, "x");
653
654 /* keep broken extracted files */
655 fr_process_add_arg (comm->process, "-kb");
656
657 if (overwrite)
658 fr_process_add_arg (comm->process, "-o+");
659 else
660 fr_process_add_arg (comm->process, "-o-");
661
662 if (skip_older)
663 fr_process_add_arg (comm->process, "-u");
664
665 if (junk_paths)
666 fr_process_add_arg (comm->process, "-ep");
667
668 add_password_arg (comm, FR_ARCHIVE (comm)->password, TRUE);
669
670 /* disable percentage indicator */
671 fr_process_add_arg (comm->process, "-Idp");
672
673 fr_process_add_arg (comm->process, "--");
674 fr_process_add_arg (comm->process, comm->filename);
675
676 if (from_file == NULL)
677 for (scan = file_list; scan; scan = scan->next)
678 fr_process_add_arg (comm->process, scan->data);
679 else
680 fr_process_add_arg_concat (comm->process, "@", from_file, NULL);
681
682 if (dest_dir != NULL)
683 fr_process_add_arg (comm->process, dest_dir);
684
685 fr_process_end_command (comm->process);
686 }
687
688
689 static void
fr_command_rar_test(FrCommand * comm)690 fr_command_rar_test (FrCommand *comm)
691 {
692 if (have_rar ())
693 fr_process_begin_command (comm->process, "rar");
694 else
695 fr_process_begin_command (comm->process, "unrar");
696
697 fr_process_add_arg (comm->process, "t");
698
699 add_password_arg (comm, FR_ARCHIVE (comm)->password, TRUE);
700
701 /* disable percentage indicator */
702 fr_process_add_arg (comm->process, "-Idp");
703
704 /* stop switches scanning */
705 fr_process_add_arg (comm->process, "--");
706
707 fr_process_add_arg (comm->process, comm->filename);
708 fr_process_end_command (comm->process);
709 }
710
711
712 static void
fr_command_rar_handle_error(FrCommand * comm,FrError * error)713 fr_command_rar_handle_error (FrCommand *comm,
714 FrError *error)
715 {
716 GList *scan;
717
718 #if 0
719 {
720 GList *scan;
721
722 for (scan = g_list_last (comm->process->err.raw); scan; scan = scan->prev)
723 g_print ("%s\n", (char*)scan->data);
724 }
725 #endif
726
727 if (error->type == FR_ERROR_NONE)
728 return;
729
730 /* ignore warnings */
731 if (error->status <= 1)
732 fr_error_clear_gerror (error);
733
734 for (scan = g_list_last (comm->process->err.raw); scan; scan = scan->prev) {
735 char *line = scan->data;
736
737 if (strstr (line, "password incorrect") != NULL) {
738 fr_error_take_gerror (error, g_error_new_literal (FR_ERROR, FR_ERROR_ASK_PASSWORD, ""));
739 break;
740 }
741
742 if (strstr (line, "password is incorrect") != NULL) {
743 fr_error_take_gerror (error, g_error_new_literal (FR_ERROR, FR_ERROR_ASK_PASSWORD, ""));
744 break;
745 }
746
747 if (strstr (line, "wrong password") != NULL) {
748 fr_error_take_gerror (error, g_error_new_literal (FR_ERROR, FR_ERROR_ASK_PASSWORD, ""));
749 break;
750 }
751
752 if (strncmp (line, "Unexpected end of archive", 25) == 0) {
753 /* FIXME: handle this type of errors at a higher level when the freeze is over. */
754 }
755
756 if (strncmp (line, "Cannot find volume", 18) == 0) {
757 char *volume_filename = g_path_get_basename (line + strlen ("Cannot find volume "));
758 fr_error_take_gerror (error, g_error_new (FR_ERROR, FR_ERROR_MISSING_VOLUME, _("Could not find the volume: %s"), volume_filename));
759
760 g_free (volume_filename);
761 break;
762 }
763 }
764 }
765
766
767 const char *rar_mime_type[] = { "application/x-cbr",
768 "application/x-rar",
769 NULL };
770
771
772 static const char **
fr_command_rar_get_mime_types(FrArchive * archive)773 fr_command_rar_get_mime_types (FrArchive *archive)
774 {
775 return rar_mime_type;
776 }
777
778
779 static FrArchiveCap
fr_command_rar_get_capabilities(FrArchive * archive,const char * mime_type,gboolean check_command)780 fr_command_rar_get_capabilities (FrArchive *archive,
781 const char *mime_type,
782 gboolean check_command)
783 {
784 FrArchiveCap capabilities;
785
786 capabilities = FR_ARCHIVE_CAN_STORE_MANY_FILES | FR_ARCHIVE_CAN_ENCRYPT | FR_ARCHIVE_CAN_ENCRYPT_HEADER;
787 if (_g_program_is_available ("rar", check_command))
788 capabilities |= FR_ARCHIVE_CAN_READ_WRITE | FR_ARCHIVE_CAN_CREATE_VOLUMES;
789 else if (_g_program_is_available ("unrar", check_command))
790 capabilities |= FR_ARCHIVE_CAN_READ;
791
792 /* multi-volumes are read-only */
793 if ((archive->files->len > 0) && archive->multi_volume && (capabilities & FR_ARCHIVE_CAN_WRITE))
794 capabilities ^= FR_ARCHIVE_CAN_WRITE;
795
796 return capabilities;
797 }
798
799
800 static const char *
fr_command_rar_get_packages(FrArchive * archive,const char * mime_type)801 fr_command_rar_get_packages (FrArchive *archive,
802 const char *mime_type)
803 {
804 return PACKAGES ("rar,unrar");
805 }
806
807
808 static void
fr_command_rar_finalize(GObject * object)809 fr_command_rar_finalize (GObject *object)
810 {
811 g_return_if_fail (object != NULL);
812 g_return_if_fail (FR_IS_COMMAND_RAR (object));
813
814 if (G_OBJECT_CLASS (fr_command_rar_parent_class)->finalize)
815 G_OBJECT_CLASS (fr_command_rar_parent_class)->finalize (object);
816 }
817
818
819 static void
fr_command_rar_class_init(FrCommandRarClass * klass)820 fr_command_rar_class_init (FrCommandRarClass *klass)
821 {
822 GObjectClass *gobject_class;
823 FrArchiveClass *archive_class;
824 FrCommandClass *command_class;
825
826 fr_command_rar_parent_class = g_type_class_peek_parent (klass);
827
828 gobject_class = G_OBJECT_CLASS (klass);
829 gobject_class->finalize = fr_command_rar_finalize;
830
831 archive_class = FR_ARCHIVE_CLASS (klass);
832 archive_class->get_mime_types = fr_command_rar_get_mime_types;
833 archive_class->get_capabilities = fr_command_rar_get_capabilities;
834 archive_class->get_packages = fr_command_rar_get_packages;
835
836 command_class = FR_COMMAND_CLASS (klass);
837 command_class->list = fr_command_rar_list;
838 command_class->add = fr_command_rar_add;
839 command_class->delete = fr_command_rar_delete;
840 command_class->extract = fr_command_rar_extract;
841 command_class->test = fr_command_rar_test;
842 command_class->handle_error = fr_command_rar_handle_error;
843 }
844
845
846 static void
fr_command_rar_init(FrCommandRar * self)847 fr_command_rar_init (FrCommandRar *self)
848 {
849 FrArchive *base = FR_ARCHIVE (self);
850
851 base->propAddCanUpdate = TRUE;
852 base->propAddCanReplace = TRUE;
853 base->propAddCanStoreFolders = TRUE;
854 base->propAddCanStoreLinks = TRUE;
855 base->propExtractCanAvoidOverwrite = TRUE;
856 base->propExtractCanSkipOlder = TRUE;
857 base->propExtractCanJunkPaths = TRUE;
858 base->propCanDeleteAllFiles = FALSE;
859 base->propPassword = TRUE;
860 base->propTest = TRUE;
861 base->propListFromFile = TRUE;
862 }
863