/* Waits for a given VFS operation to complete without halting the UI */
static gboolean
vfs_data_wait_results(VfsAsyncHandle* ah, gboolean errors)
{
    VfsAsyncOp op;
    gint code;
    
    seahorse_util_wait_until (ah->state != VFS_ASYNC_PROCESSING);

    op = ah->operation;
    ah->operation = VFS_OP_NONE;
    
    /* Cancelling looks like an error to our caller */
    if (ah->state == VFS_ASYNC_CANCELLED) {
        errno = 0;
        return FALSE;
    }
        
    g_assert (ah->state == VFS_ASYNC_READY);
    
    /* There was no operation going on, result codes are not relevant */
    if (op == VFS_OP_NONE)
        return TRUE;
    
    /* No error result */
    if (!ah->error) {
	    return TRUE;
    }

    code = -1;
    if (ah->error->domain == G_IO_ERROR)
        code = ah->error->code;
    
    if (code == G_IO_ERROR_CANCELLED) {
        vfs_data_cancel (ah);
        errno = 0;
        return FALSE;
    }
    
    /* Check for error codes */
    if(errors) {
        switch(code) {
        #define GIO_TO_SYS_ERR(v, s)    \
            case v: errno = s; break;
        GIO_TO_SYS_ERR (G_IO_ERROR_FAILED, EIO);
        GIO_TO_SYS_ERR (G_IO_ERROR_NOT_FOUND, ENOENT);
        GIO_TO_SYS_ERR (G_IO_ERROR_EXISTS, EEXIST);
        GIO_TO_SYS_ERR (G_IO_ERROR_IS_DIRECTORY, EISDIR);
        GIO_TO_SYS_ERR (G_IO_ERROR_NOT_DIRECTORY, ENOTDIR);
        GIO_TO_SYS_ERR (G_IO_ERROR_NOT_EMPTY, ENOTEMPTY);
        GIO_TO_SYS_ERR (G_IO_ERROR_NOT_REGULAR_FILE, EINVAL);
        GIO_TO_SYS_ERR (G_IO_ERROR_NOT_SYMBOLIC_LINK, EINVAL);
        GIO_TO_SYS_ERR (G_IO_ERROR_NOT_MOUNTABLE_FILE, EINVAL);
        GIO_TO_SYS_ERR (G_IO_ERROR_FILENAME_TOO_LONG, ENAMETOOLONG);
        GIO_TO_SYS_ERR (G_IO_ERROR_INVALID_FILENAME, EINVAL);
        GIO_TO_SYS_ERR (G_IO_ERROR_TOO_MANY_LINKS, EMLINK);
        GIO_TO_SYS_ERR (G_IO_ERROR_NO_SPACE, ENOSPC);
        GIO_TO_SYS_ERR (G_IO_ERROR_INVALID_ARGUMENT, EINVAL);
        GIO_TO_SYS_ERR (G_IO_ERROR_PERMISSION_DENIED, EACCES);
        GIO_TO_SYS_ERR (G_IO_ERROR_NOT_SUPPORTED, EOPNOTSUPP);
        GIO_TO_SYS_ERR (G_IO_ERROR_NOT_MOUNTED, EIO);
        GIO_TO_SYS_ERR (G_IO_ERROR_ALREADY_MOUNTED, EIO);
        GIO_TO_SYS_ERR (G_IO_ERROR_CLOSED, EINVAL);
        GIO_TO_SYS_ERR (G_IO_ERROR_CANCELLED, EIO);
        GIO_TO_SYS_ERR (G_IO_ERROR_PENDING, EAGAIN);
        GIO_TO_SYS_ERR (G_IO_ERROR_READ_ONLY, EPERM);
        GIO_TO_SYS_ERR (G_IO_ERROR_CANT_CREATE_BACKUP, EIO);
        GIO_TO_SYS_ERR (G_IO_ERROR_WRONG_ETAG, EIO);
        GIO_TO_SYS_ERR (G_IO_ERROR_TIMED_OUT, EIO);
        GIO_TO_SYS_ERR (G_IO_ERROR_WOULD_RECURSE, EIO);
        GIO_TO_SYS_ERR (G_IO_ERROR_BUSY, EBUSY);
        GIO_TO_SYS_ERR (G_IO_ERROR_WOULD_BLOCK, EWOULDBLOCK);
        GIO_TO_SYS_ERR (G_IO_ERROR_HOST_NOT_FOUND, ENOENT);
        GIO_TO_SYS_ERR (G_IO_ERROR_WOULD_MERGE, EIO);
        GIO_TO_SYS_ERR (G_IO_ERROR_FAILED_HANDLED, EIO);
        default: 
            errno = EIO;
            break;
        };
    }
            
    /* When errors on open we look cancelled */
    if(op == VFS_OP_OPENING)
        ah->state = VFS_ASYNC_CANCELLED;

    return FALSE;
}
static gboolean
step_operation (FilesCtx *ctx,
                SeahorseToolMode *mode,
                GError **err)
{
    SeahorsePGPOperation *pop = NULL;
    gpgme_data_t data = NULL;
    gboolean ret = FALSE;

    SeahorseOperation *op;
    FileInfo *finfo;
    GList *l;
    gchar *filename;

    /* Reset our done counter */
    ctx->done = 0;

    for (l = ctx->finfos; l; l = g_list_next (l)) {

        finfo = (FileInfo*)l->data;
        if (!finfo || !finfo->file)
            continue;

        ctx->cur = finfo;

        /* A new operation for each context */
        pop = seahorse_pgp_operation_new (NULL);
        op = SEAHORSE_OPERATION (pop);

        data = seahorse_vfs_data_create_full (finfo->file, SEAHORSE_VFS_READ,
                                              (SeahorseVfsProgressCb)progress_cb,
                                              ctx, err);
        if (!data)
            goto finally;

        /* Inhibit popping up of progress dialog */
        seahorse_tool_progress_block (TRUE);

        /* Embed filename during encryption */
        if (mode_encrypt)
        {
            filename = g_file_get_basename (finfo->file);
            gpgme_data_set_file_name (data, filename);
            g_free (filename);
        }

        /* The start callback */
        if (mode->startcb) {
            if (!(mode->startcb) (mode, finfo->uri, data, pop, err))
                goto finally;
        }

        /* Let progress dialog pop up */
        seahorse_tool_progress_block (FALSE);

        /* Run until the operation completes */
        seahorse_util_wait_until ((!seahorse_operation_is_running (op) ||
                                   !seahorse_tool_progress_check ()));

        /* If cancel then reflect that */
        if (seahorse_operation_is_running (op)) {
            seahorse_operation_cancel (op);
            goto finally;
        }

        if (!seahorse_operation_is_successful (op)) {
            seahorse_operation_copy_error (op, err);
            goto finally;
        }

        /* The done callback */
        if (mode->donecb) {
            if (!(mode->donecb) (mode, finfo->uri, data, pop, err))
                goto finally;
        }

        ctx->done += g_file_info_get_size (finfo->info);
        ctx->cur = NULL;

        g_object_unref (pop);
        pop = NULL;

        gpgme_data_release (data);
        data = NULL;
    }

    seahorse_tool_progress_update (1.0, "");
    ret = TRUE;

finally:
    if (pop)
        g_object_unref (pop);
    if (data)
        gpgme_data_release (data);

    return ret;
}