Home | History | Annotate | Download | only in src
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #ifdef HAVE_CONFIG_H
     28 #include <config.h>
     29 #endif
     30 
     31 #include <string.h>
     32 #include <glib.h>
     33 #include <stdio.h>
     34 #include <sys/stat.h>
     35 #include <sys/types.h>
     36 #include <fcntl.h>
     37 
     38 #include <glib/gi18n.h>
     39 #include <gtk/gtk.h>
     40 
     41 #include "fsexam-debug.h"
     42 #include "fsexam-header.h"
     43 
     44 void        cb_text_buffer_changed (GtkTextBuffer *buffer, gpointer data);
     45 
     46 static void fsexam_dryrun_base_init (gpointer g_class);
     47 
     48 static void dryrun_file_instance_init (GTypeInstance *instance,
     49         gpointer g_class);
     50 static void dryrun_file_interface_init (gpointer g_iface,
     51         gpointer iface_data);
     52 static void dryrun_file_class_init (GObjectClass *klass);
     53 
     54 static void dryrun_buffer_instance_init (GTypeInstance *instance,
     55         gpointer g_class);
     56 static void dryrun_buffer_interface_init (gpointer g_iface,
     57         gpointer iface_data);
     58 static void dryrun_buffer_class_init (GObjectClass *klass);
     59 
     60 static gboolean fsexam_dryrun_write_path (FsexamDryrun *, const gchar *);
     61 
     62 static gboolean fsexam_dryrun_write_candidate (FsexamDryrun *info,
     63         const gchar *encoding_name,
     64         const gchar *sample);
     65 
     66 /* FsexamDryrun Interface Implementation */
     67 static void
     68 fsexam_dryrun_base_init (gpointer g_class)
     69 {
     70     static gboolean initialized = FALSE;
     71 
     72     if (!initialized) {
     73         initialized = TRUE;
     74     }
     75 
     76     return;
     77 }
     78 
     79 GType
     80 fsexam_dryrun_get_type (void)
     81 {
     82     static GType type = 0;
     83 
     84     if (type == 0) {
     85         static const GTypeInfo info = {
     86             sizeof (FsexamDryrunInterface),
     87             fsexam_dryrun_base_init,    /* base_init */
     88             NULL,                       /* bsae_finalize */
     89             NULL,                       /* class_init */
     90             NULL,                       /* class_finalize */
     91             NULL,                       /* class_data */
     92             0,                          /* sizeof (Instance) */
     93             0,                          /* n_preallocs */
     94             NULL,                       /* instance_init */
     95         };
     96 
     97         type = g_type_register_static (G_TYPE_INTERFACE,
     98                 "FsexamDryrun",
     99                 &info,
    100                 0);
    101     }
    102 
    103     return type;
    104 }
    105 
    106 gboolean
    107 fsexam_dryrun_write (FsexamDryrun *self, const gchar *string)
    108 {
    109     return FSEXAM_DRYRUN_GET_INTERFACE (self)->write (self, string);
    110 }
    111 
    112 gboolean
    113 fsexam_dryrun_read (FsexamDryrun *self, gchar *buf, guint size)
    114 {
    115     return FSEXAM_DRYRUN_GET_INTERFACE (self)->read (self, buf, size);
    116 }
    117 
    118 /* --- Dryrun implementation on file --- */
    119 static void
    120 dryrun_file_finalize (GObject *object)
    121 {
    122     FsexamDryrunFile *dryrun_file = FSEXAM_DRYRUN_FILE (object);
    123 
    124     if (dryrun_file && dryrun_file->fp) {
    125         fclose (dryrun_file->fp);
    126         dryrun_file->fp = NULL;
    127     }
    128 
    129     return;
    130 }
    131 
    132 GType
    133 fsexam_dryrun_file_get_type (void)
    134 {
    135     static GType type = 0;
    136 
    137     if (type == 0) {
    138         static const GTypeInfo info = {
    139             sizeof (FsexamDryrunFileClass),
    140             NULL,   /* base_init */
    141             NULL,   /* base_finalize */
    142             (GClassInitFunc) dryrun_file_class_init,
    143             NULL,   /* class_finalize */
    144             NULL,   /* class_data */
    145             sizeof (FsexamDryrunFile),
    146             0,      /* n_preallocs */
    147             (GInstanceInitFunc) dryrun_file_instance_init,
    148         };
    149 
    150         static const GInterfaceInfo dryrun_info = {
    151             (GInterfaceInitFunc) dryrun_file_interface_init,/* interface_init */
    152             NULL,   /* interface_finalize */
    153             NULL,   /* interface_data */
    154         };
    155 
    156         type = g_type_register_static (G_TYPE_OBJECT, "FsexamDryrunFile", &info, 0);
    157         g_type_add_interface_static (type, FSEXAM_TYPE_DRYRUN, &dryrun_info);
    158     }
    159 
    160     return type;
    161 }
    162 
    163 /* write callback implementation of DryrunFile */
    164 static gboolean
    165 dryrun_file_write (FsexamDryrunFile *self, const gchar *string)
    166 {
    167     gboolean ret = TRUE;
    168 
    169     if (fputs (string, self->fp) < 0)
    170         ret = FALSE;
    171 
    172     return ret;
    173 }
    174 
    175 static gboolean
    176 dryrun_file_read (FsexamDryrunFile *self, gchar *buf, guint size)
    177 {
    178     gboolean ret = TRUE;
    179 
    180     if (fgets (buf, size, self->fp) == NULL)
    181         ret = FALSE;
    182 
    183     return ret;
    184 }
    185 
    186 static void
    187 dryrun_file_interface_init (gpointer g_iface, gpointer iface_data)
    188 {
    189     FsexamDryrunInterface *iface = (FsexamDryrunInterface *)g_iface;
    190 
    191     iface->write = (gboolean (*) (FsexamDryrun *, const gchar *))dryrun_file_write;
    192     iface->read = (gboolean (*) (FsexamDryrun *, gchar *, guint)) dryrun_file_read;
    193 
    194     return;
    195 }
    196 
    197 static void
    198 dryrun_file_instance_init (GTypeInstance *instance, gpointer g_class)
    199 {
    200     FsexamDryrunFile *self = FSEXAM_DRYRUN_FILE (instance);
    201 
    202     self->fp = NULL;
    203 
    204     return;
    205 }
    206 
    207 static void
    208 dryrun_file_class_init (GObjectClass *klass)
    209 {
    210     klass->finalize = dryrun_file_finalize;
    211 
    212     return;
    213 }
    214 
    215 FsexamDryrun *
    216 fsexam_dryrun_file_new (const gchar *filename, gboolean readonly)
    217 {
    218     FsexamDryrunFile *dryrun = NULL;
    219 
    220     if (filename == NULL)
    221         return NULL;
    222 
    223     dryrun = g_object_new (FSEXAM_TYPE_DRYRUN_FILE, NULL);
    224     dryrun->fp = fopen (filename, readonly ? "r" : "w");
    225 
    226     if (dryrun->fp == NULL) {
    227         g_object_unref (dryrun);
    228         return NULL;
    229     }
    230 
    231     return FSEXAM_DRYRUN (dryrun);
    232 }
    233 
    234 /* --- Widget implementation for dryrun --- */
    235 GType
    236 fsexam_dryrun_buffer_get_type (void)
    237 {
    238     static GType type = 0;
    239 
    240     if (type == 0) {
    241         static const GTypeInfo info = {
    242             sizeof (FsexamDryrunBufferClass),
    243             NULL,   /* base_init */
    244             NULL,   /* base_finalize */
    245             (GClassInitFunc) dryrun_buffer_class_init,
    246             NULL,   /* class_finalize */
    247             NULL,   /* class_data */
    248             sizeof (FsexamDryrunBuffer),
    249             0,      /* n_preallocs */
    250             (GInstanceInitFunc) dryrun_buffer_instance_init,
    251         };
    252 
    253         static const GInterfaceInfo dryrun_info = {
    254             (GInterfaceInitFunc) dryrun_buffer_interface_init,
    255             NULL,   /* interface_finalize */
    256             NULL,   /* interface_data */
    257         };
    258 
    259         type = g_type_register_static (G_TYPE_OBJECT, "FsexamDryrunBuffer", &info, 0);
    260         g_type_add_interface_static (type, FSEXAM_TYPE_DRYRUN, &dryrun_info);
    261     }
    262 
    263     return type;
    264 }
    265 
    266 /*
    267  * Create mark and connect signal handler for GtkTextBuffer
    268  */
    269 static void
    270 setup_text_buffer (GtkTextBuffer *buffer)
    271 {
    272     GtkTextIter iter;
    273 
    274     if (buffer == NULL)
    275         return;
    276 
    277     gtk_text_buffer_get_end_iter (buffer, &iter);
    278     gtk_text_buffer_create_mark (buffer, "end_mark", &iter, FALSE);
    279 
    280     g_signal_connect (G_OBJECT (buffer), "changed",
    281                       G_CALLBACK (cb_text_buffer_changed), NULL);
    282 
    283     return;
    284 }
    285 
    286 static gboolean
    287 dryrun_buffer_write (FsexamDryrunBuffer *self, const gchar *string)
    288 {
    289     GtkTextIter     iter;
    290 
    291     if (self->buffer == NULL)
    292         return FALSE;
    293 
    294     gtk_text_buffer_get_end_iter (self->buffer, &iter);
    295     gtk_text_buffer_insert (self->buffer, &iter, string, -1);
    296 
    297     return TRUE;
    298 }
    299 
    300 /*
    301  * read one line from text buffer and increase line number
    302  */
    303 static gboolean
    304 dryrun_buffer_read (FsexamDryrunBuffer *self, gchar *buf, guint size)
    305 {
    306     gboolean    ret = TRUE;
    307     guint       line_count;
    308     GtkTextIter start, end;
    309     gchar       *text = NULL;
    310 
    311     line_count = (guint) gtk_text_buffer_get_line_count (self->buffer);
    312     line_count --;  /* The last line is empty line */
    313 
    314     if (self->current_line >= line_count) /* EOF */
    315         return FALSE;
    316 
    317     gtk_text_buffer_get_iter_at_line (self->buffer,
    318             &start,
    319             self->current_line);
    320     gtk_text_buffer_get_iter_at_line (self->buffer,
    321             &end,
    322             self->current_line + 1);
    323 
    324     text = gtk_text_buffer_get_text (self->buffer, &start, &end, FALSE);
    325 
    326     strlcpy (buf, text, size);
    327 
    328     g_free (text);
    329     self->current_line++;
    330 
    331     return ret;
    332 }
    333 
    334 static void
    335 dryrun_buffer_interface_init (gpointer g_iface, gpointer iface_data)
    336 {
    337     FsexamDryrunInterface *iface = (FsexamDryrunInterface *)g_iface;
    338 
    339     iface->write = (gboolean (*) (FsexamDryrun *, const gchar *))dryrun_buffer_write;
    340     iface->read = (gboolean (*) (FsexamDryrun *, gchar *, guint)) dryrun_buffer_read;
    341 
    342     return;
    343 }
    344 
    345 static void
    346 dryrun_buffer_instance_init (GTypeInstance *instance, gpointer g_class)
    347 {
    348     FsexamDryrunBuffer *self = FSEXAM_DRYRUN_BUFFER (instance);
    349 
    350     self->buffer = NULL;
    351     self->current_line = 0;
    352 
    353     return;
    354 }
    355 
    356 static void
    357 dryrun_buffer_finalize (GObject *object)
    358 {
    359     return;
    360 }
    361 
    362 static void
    363 dryrun_buffer_class_init (GObjectClass *klass)
    364 {
    365     klass->finalize = dryrun_buffer_finalize;
    366 
    367     return;
    368 }
    369 
    370 FsexamDryrun *
    371 fsexam_dryrun_buffer_new (void)
    372 {
    373     FsexamDryrunBuffer *dryrun = NULL;
    374 
    375     dryrun = g_object_new (FSEXAM_TYPE_DRYRUN_BUFFER, NULL);
    376 
    377     return FSEXAM_DRYRUN (dryrun);
    378 }
    379 
    380 FsexamDryrun *
    381 fsexam_dryrun_buffer_new_with_buffer (GtkTextBuffer *buffer)
    382 {
    383     FsexamDryrunBuffer *dryrun = NULL;
    384 
    385     dryrun = g_object_new (FSEXAM_TYPE_DRYRUN_BUFFER, NULL);
    386 
    387     if (buffer != NULL) {
    388         dryrun->buffer = buffer;
    389         setup_text_buffer (buffer);
    390     }
    391 
    392     return FSEXAM_DRYRUN (dryrun);
    393 }
    394 
    395 void
    396 fsexam_dryrun_buffer_clear_buffer (FsexamDryrunBuffer *buffer)
    397 {
    398     GtkTextIter start, end;
    399 
    400     gtk_text_buffer_get_start_iter (buffer->buffer, &start);
    401     gtk_text_buffer_get_end_iter (buffer->buffer, &end);
    402     gtk_text_buffer_delete (buffer->buffer, &start, &end);
    403 
    404     buffer->current_line = 0;
    405 
    406     return;
    407 }
    408 
    409 void
    410 fsexam_dryrun_buffer_set_buffer (FsexamDryrunBuffer *buffer,
    411         GtkTextBuffer *buf)
    412 {
    413     if (buffer == NULL)
    414         return;
    415 
    416     buffer->buffer = buf;
    417     setup_text_buffer (buffer->buffer);
    418 
    419     return;
    420 }
    421 
    422 void
    423 fsexam_dryrun_buffer_set_current_line (FsexamDryrunBuffer *buffer, guint line_no)
    424 {
    425     if (buffer == NULL)
    426         return;
    427 
    428     buffer->current_line = line_no;
    429 
    430     return;
    431 }
    432 
    433 /*
    434  * Write the full file path into dryrun file
    435  */
    436 static gboolean
    437 fsexam_dryrun_write_path (FsexamDryrun *info, const gchar *path)
    438 {
    439     if ((NULL == path) || (NULL == info))
    440         return FALSE;
    441 
    442     if (g_utf8_validate (path, -1, NULL)){
    443         if (! fsexam_dryrun_write (info, path)){
    444             fsexam_errno = ERR_CANNOT_WRITE_DRYRUN;
    445             goto fail;
    446         }
    447     }else{
    448         gchar *uri = NULL;
    449         uri = g_filename_to_uri (path, NULL, NULL);
    450         if (NULL == uri){
    451             fsexam_errno = ERR_CANNOT_CONVERT_TO_URI;
    452             goto fail;
    453         }
    454         if (! fsexam_dryrun_write (info, uri) < 0){
    455             fsexam_errno = ERR_CANNOT_WRITE_DRYRUN;
    456             g_free (uri);
    457             goto fail;
    458         }
    459         g_free (uri);
    460     }
    461 
    462     fsexam_dryrun_write (info, "\n");
    463 
    464     return TRUE;
    465 
    466 fail:
    467     return FALSE;
    468 }
    469 
    470 static gboolean
    471 fsexam_dryrun_write_candidate (FsexamDryrun *info,
    472                                const gchar *encoding_name,
    473                                const gchar *sample)
    474 {
    475     if ((NULL == info) || (NULL == sample) || (NULL == encoding_name))
    476         return FALSE;
    477 
    478     if (! fsexam_dryrun_write (info, "\t")) {
    479         fsexam_errno = ERR_CANNOT_WRITE_DRYRUN;
    480         return FALSE;
    481     }
    482 
    483     fsexam_dryrun_write (info, encoding_name);
    484     fsexam_dryrun_write (info, "\t");
    485     fsexam_dryrun_write (info, sample);
    486     fsexam_dryrun_write (info, "\n");
    487 
    488     return TRUE;
    489 }
    490 
    491 gboolean
    492 fsexam_dryrun_write_msg (FsexamDryrun *info, const gchar *msg)
    493 {
    494     if ((NULL == info) || (NULL == msg))
    495         return FALSE;
    496 
    497     if (! fsexam_dryrun_write (info, "\t")) {
    498         fsexam_errno = ERR_CANNOT_WRITE_DRYRUN;
    499         return FALSE;
    500     }
    501 
    502     fsexam_dryrun_write (info, msg);
    503     fsexam_dryrun_write (info, "\n");
    504 
    505     return TRUE;
    506 }
    507 
    508 gboolean
    509 fsexam_dryrun_write_convtype (FsexamDryrun *info, ConvType type)
    510 {
    511     g_return_val_if_fail ((info != NULL), FALSE);
    512 
    513     if (type == ConvName)
    514         fsexam_dryrun_write (info, "Name conversion\n");
    515     else
    516         fsexam_dryrun_write (info, "Content conversion\n");
    517 
    518     return TRUE;
    519 }
    520 
    521 /*
    522  * Get the conversion type, and set fsexam_errno if invalid
    523  */
    524 gboolean
    525 fsexam_dryrun_get_convtype (FsexamDryrun *info, ConvType *type)
    526 {
    527     const gint TYPE_LENGTH = 80;
    528     gchar convtype[TYPE_LENGTH];
    529     gchar *strip = NULL;
    530 
    531     if (! fsexam_dryrun_read (info, convtype, sizeof (convtype))){
    532         fsexam_errno = ERR_DRYRUN_FILE_INVALID;
    533         return FALSE;
    534     }
    535 
    536     strip = g_strstrip (convtype);
    537 
    538     if (strcmp (strip, "Name conversion") == 0)
    539         *type = ConvName;
    540     else if (strcmp (strip, "Content conversion") == 0)
    541         *type = ConvContent;
    542     else
    543         fsexam_errno = ERR_DRYRUN_FILE_INVALID;
    544 
    545     return TRUE;
    546 }
    547 
    548 /*
    549  *  Analyze dryrun result file, add Dryrun_item which represent
    550  *  user selected encoding into GSList result.
    551  */
    552 gboolean
    553 fsexam_dryrun_process (FsexamDryrun *info, GSList **result)
    554 {
    555     g_return_val_if_fail (info != NULL, FALSE);
    556 
    557     gchar    linebuf [PATH_MAX + 20];
    558     gchar    *path = NULL, *encoding = NULL, *sample = NULL, *ptr = NULL;
    559     GSList   *slist = NULL;
    560     gboolean metpath = FALSE, metcode = FALSE, tab = FALSE;
    561     gboolean ret = FALSE;
    562 
    563     while (fsexam_dryrun_read (info, linebuf, sizeof (linebuf))) {
    564         if (linebuf[strlen (linebuf) - 1] == '\n')
    565             linebuf[strlen (linebuf) - 1] = '\0';
    566 
    567         /* remove leading and trailing white space */
    568         if ((ptr = str_compress (linebuf, &tab)) == NULL) {
    569             continue;                       /* Empty line */
    570         }
    571 
    572         /*
    573          * Some files may not need convert at all, or have no
    574          * proper encoding. bypass it and continue.
    575          */
    576         if ((strcmp (ptr, FSEXAM_DRYRUN_NO_NEED_CONVERT) == 0)
    577                 || (strcmp (ptr, FSEXAM_DRYRUN_NO_PROPER_ENCODING) == 0)) {
    578             if (!metpath) {
    579                 fsexam_errno = ERR_DRYRUN_FILE_INVALID;
    580                 goto done;
    581             }
    582 
    583             g_free (path);
    584             path = NULL;
    585             metpath = FALSE;
    586             continue;
    587         }
    588 
    589         if (tab) {
    590             Dryrun_item *item = NULL;
    591 
    592             if (!metpath) {
    593                 if (metcode) {      /* metpath will be false after first candidate */
    594                     continue;       /* ignore non-first encoding candidate */
    595                 }else{
    596                     fsexam_errno = ERR_DRYRUN_FILE_INVALID;
    597                     goto done;
    598                 }
    599             }
    600 
    601             metcode = TRUE;
    602 
    603             str_split (ptr, &encoding, &sample);
    604             if ((encoding2id (encoding) == -1) || (sample == NULL)) {
    605                 fsexam_errno = ERR_DRYRUN_FILE_INVALID;
    606                 goto done;
    607             }
    608 
    609             /*
    610              * Found one valid path/encoding pair.
    611              */
    612             if ((item = g_new0 (Dryrun_item, 1)) == NULL) {
    613                 fsexam_errno = ERR_NO_MEMORY;
    614                 goto done;
    615             }
    616 
    617             item->path = path;
    618             item->encoding = encoding;
    619 
    620             slist = g_slist_prepend (slist, item);
    621 
    622             g_free (sample);
    623             path = NULL;
    624             encoding = NULL;
    625             sample = NULL;
    626 
    627             metpath = FALSE;
    628         }else{
    629             if (metpath) {
    630                 fsexam_errno = ERR_DRYRUN_FILE_INVALID;
    631                 goto done;
    632             }
    633 
    634             if ('/' == *ptr) {
    635                 path = g_strdup (ptr);
    636             }else{
    637                 path = g_filename_from_uri (ptr, NULL, NULL);
    638             }
    639 
    640             if (NULL == path) {
    641                 fsexam_errno = ERR_DRYRUN_FILE_INVALID;
    642                 goto done;
    643             }
    644 
    645             metpath = TRUE;
    646             metcode = FALSE;
    647         }
    648     }
    649 
    650     if (NULL == slist)
    651         fsexam_errno = ERR_DRYRUN_FILE_INVALID;
    652     else
    653         slist = g_slist_reverse (slist);
    654 
    655     *result = slist;        /* caller must pass in this param */
    656     ret = TRUE;
    657 
    658 done:
    659     g_free (path);
    660     g_free (encoding);
    661     g_free (sample);
    662 
    663     return ret;
    664 }
    665 
    666 void
    667 fsexam_dryrun_item_slist_free (GSList *slist)
    668 {
    669     if (NULL == slist)
    670         return;
    671 
    672     while (slist != NULL) {
    673         Dryrun_item *item = slist->data;
    674 
    675         g_free (item->path);
    676         g_free (item->encoding);
    677         g_free (item);
    678 
    679         slist = slist->next;
    680     }
    681 
    682     g_slist_free (slist);
    683 
    684     return;
    685 }
    686 
    687 /*
    688  * Write one dryrun item into file
    689  */
    690 gboolean
    691 fsexam_dryrun_puts (FsexamDryrun *info,
    692                     const gchar *fullpath,
    693                     Score score,            /* total score */
    694                     GList *encoding_list,
    695                     ConvType convtype)
    696 {
    697     gboolean    ret = TRUE;
    698 
    699     if ((NULL == info) || (NULL == fullpath) || (NULL == encoding_list))
    700         return FALSE;
    701 
    702     if (! fsexam_dryrun_write_path (info, fullpath)) {
    703         return FALSE;
    704     }
    705 
    706     if (score == FAIL){
    707         if (! fsexam_dryrun_write_msg (info,
    708                                       _(FSEXAM_DRYRUN_NO_PROPER_ENCODING))){
    709             fsexam_errno = ERR_CANNOT_WRITE_DRYRUN;
    710             ret = FALSE;
    711         }
    712     }else if (score == ORIGINAL){
    713         if (! fsexam_dryrun_write_msg (info,
    714                                        _(FSEXAM_DRYRUN_NO_NEED_CONVERT))) {
    715             fsexam_errno = ERR_CANNOT_WRITE_DRYRUN;
    716             ret = FALSE;
    717         }
    718     }else{
    719         while (encoding_list) {
    720             Encoding  *encoding = NULL;
    721             gchar     *sample = NULL;
    722 
    723             encoding = (Encoding *)encoding_list->data;
    724             encoding_list = g_list_next (encoding_list);
    725 
    726             if ((encoding->score == FAIL) || (encoding->score == ORIGINAL)){
    727                 continue;
    728             }
    729 
    730             if (convtype == ConvName) {
    731                 sample = encoding->u.converted_text;
    732             }else{
    733                 sample = encoding->u.contents;
    734             }
    735 
    736             if (! fsexam_dryrun_write_candidate (info,
    737                                     id2encoding (encoding->encodingID),
    738                                     sample)) {
    739                 fsexam_errno = ERR_CANNOT_WRITE_DRYRUN;
    740                 ret = FALSE;
    741             }
    742 /*      BIG bug: double free
    743             if (convtype != ConvName)
    744                 g_free (sample);
    745 */
    746         }
    747     }
    748 
    749     return ret;
    750 }
    751