/** * Completion idle function. This function is called by the main (UI) thread * during UI idle time while an address search is in progress. Items from the * display queue are processed and appended to the address list. * * \param data Target completion window to receive email addresses. * \return <i>TRUE</i> to ensure that idle event do not get ignored. */ static gboolean addrcompl_idle( gpointer data ) { GList *node; gchar *address; /* Process all entries in display queue */ pthread_mutex_lock( & _completionMutex_ ); if( _displayQueue_ ) { node = _displayQueue_; while( node ) { address = node->data; /* g_print( "address ::: %s :::\n", address ); */ addrcompl_add_entry( _compWindow_, address ); g_free( address ); node = g_list_next( node ); } g_list_free( _displayQueue_ ); _displayQueue_ = NULL; } pthread_mutex_unlock( & _completionMutex_ ); claws_do_idle(); return TRUE; }
static void pgpview_show_mime_part(TextView *textview, MimeInfo *partinfo) { GtkTextView *text; GtkTextBuffer *buffer; GtkTextIter iter; gpgme_data_t sigdata = NULL; gpgme_verify_result_t sigstatus = NULL; gpgme_ctx_t ctx = NULL; gpgme_key_t key = NULL; gpgme_signature_t sig = NULL; gpgme_error_t err = 0; gboolean imported = FALSE; if (!partinfo) return; textview_set_font(textview, NULL); textview_clear(textview); text = GTK_TEXT_VIEW(textview->text); buffer = gtk_text_view_get_buffer(text); gtk_text_buffer_get_start_iter(buffer, &iter); err = gpgme_new (&ctx); if (err) { debug_print("err : %s\n", gpgme_strerror(err)); textview_show_mime_part(textview, partinfo); return; } sigdata = sgpgme_data_from_mimeinfo(partinfo); if (!sigdata) { g_warning("no sigdata"); textview_show_mime_part(textview, partinfo); return; } /* Here we do not care about what data we attempt to verify with the * signature, or about result of the verification - all we care about * is that we find out ID of the key used to make this signature. */ sigstatus = sgpgme_verify_signature(ctx, sigdata, NULL, sigdata); if (!sigstatus || sigstatus == GINT_TO_POINTER(-GPG_ERR_SYSTEM_ERROR)) { g_warning("no sigstatus"); textview_show_mime_part(textview, partinfo); return; } sig = sigstatus->signatures; if (!sig) { g_warning("no sig"); textview_show_mime_part(textview, partinfo); return; } gpgme_get_key(ctx, sig->fpr, &key, 0); if (!key) { gchar *gpgbin = get_gpg_executable_name(); gchar *cmd = g_strdup_printf("\"%s\" --batch --no-tty --recv-keys %s", (gpgbin ? gpgbin : "gpg"), sig->fpr); AlertValue val = G_ALERTDEFAULT; if (!prefs_common_get_prefs()->work_offline) { val = alertpanel(_("Key import"), _("This key is not in your keyring. Do you want " "Claws Mail to try and import it from a " "keyserver?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL, ALERTFOCUS_SECOND); GTK_EVENTS_FLUSH(); } if (val == G_ALERTDEFAULT) { TEXTVIEW_INSERT(_("\n Key ID ")); TEXTVIEW_INSERT(sig->fpr); TEXTVIEW_INSERT(":\n\n"); TEXTVIEW_INSERT(_(" This key is not in your keyring.\n")); TEXTVIEW_INSERT(_(" It should be possible to import it ")); if (prefs_common_get_prefs()->work_offline) TEXTVIEW_INSERT(_("when working online,\n or ")); TEXTVIEW_INSERT(_("with the following command: \n\n ")); TEXTVIEW_INSERT(cmd); } else { TEXTVIEW_INSERT(_("\n Importing key ID ")); TEXTVIEW_INSERT(sig->fpr); TEXTVIEW_INSERT(":\n\n"); main_window_cursor_wait(mainwindow_get_mainwindow()); textview_cursor_wait(textview); GTK_EVENTS_FLUSH(); #ifndef G_OS_WIN32 int res = 0; pid_t pid = 0; pid = fork(); if (pid == -1) { res = -1; } else if (pid == 0) { /* son */ gchar **argv; argv = strsplit_with_quote(cmd, " ", 0); res = execvp(argv[0], argv); perror("execvp"); exit(255); } else { int status = 0; time_t start_wait = time(NULL); res = -1; do { if (waitpid(pid, &status, WNOHANG) == 0 || !WIFEXITED(status)) { usleep(200000); } else { res = WEXITSTATUS(status); break; } if (time(NULL) - start_wait > 9) { debug_print("SIGTERM'ing gpg %d\n", pid); kill(pid, SIGTERM); } if (time(NULL) - start_wait > 10) { debug_print("SIGKILL'ing gpg %d\n", pid); kill(pid, SIGKILL); break; } } while(1); } debug_print("res %d\n", res); if (res == 0) imported = TRUE; #else /* We need to call gpg in a separate thread, so that waiting for * it to finish does not block the UI. */ pthread_t pt; struct _ImportCtx *ctx = malloc(sizeof(struct _ImportCtx)); ctx->done = FALSE; ctx->exitcode = STILL_ACTIVE; ctx->cmd = cmd; if (pthread_create(&pt, NULL, _import_threaded, (void *)ctx) != 0) { debug_print("Couldn't create thread, continuing unthreaded.\n"); _import_threaded(ctx); } else { debug_print("Thread created, waiting for it to finish...\n"); while (!ctx->done) claws_do_idle(); } debug_print("Thread finished.\n"); pthread_join(pt, NULL); if (ctx->exitcode == 0) { imported = TRUE; } g_free(ctx); #endif main_window_cursor_normal(mainwindow_get_mainwindow()); textview_cursor_normal(textview); if (imported) { TEXTVIEW_INSERT(_(" This key has been imported to your keyring.\n")); } else { TEXTVIEW_INSERT(_(" This key couldn't be imported to your keyring.\n")); TEXTVIEW_INSERT(_(" Key servers are sometimes slow.\n")); TEXTVIEW_INSERT(_(" You can try to import it manually with the command:\n\n ")); TEXTVIEW_INSERT(cmd); } } g_free(cmd); return; } else { TEXTVIEW_INSERT(_("\n Key ID ")); #if defined GPGME_VERSION_NUMBER && GPGME_VERSION_NUMBER >= 0x010700 TEXTVIEW_INSERT(key->fpr); #else TEXTVIEW_INSERT(sig->fpr); #endif TEXTVIEW_INSERT(":\n\n"); TEXTVIEW_INSERT(_(" This key is in your keyring.\n")); } gpgme_data_release(sigdata); gpgme_release(ctx); textview_show_icon(textview, GTK_STOCK_DIALOG_AUTHENTICATION); }
gchar *filesel_select_file_save(const gchar *title, const gchar *path) { gboolean ret; gchar *str, *filename = NULL; gunichar2 *filename16, *path16, *title16; glong conv_items; GError *error = NULL; WinChooserCtx *ctx; #ifdef USE_PTHREAD pthread_t pt; #endif /* Find the filename part, if any */ if (path == NULL || path[strlen(path)-1] == G_DIR_SEPARATOR) { filename = ""; } else if ((filename = strrchr(path, G_DIR_SEPARATOR)) != NULL) { filename++; } else { filename = (char *) path; } /* Convert it to UTF-16. */ filename16 = g_utf8_to_utf16(filename, -1, NULL, &conv_items, &error); if (error != NULL) { alertpanel_error(_("Could not convert attachment name to UTF-16:\n\n%s"), error->message); debug_print("filename '%s' conversion to UTF-16 failed\n", filename); g_error_free(error); return NULL; } /* Path needs to be converted to UTF-16, so that the native chooser * can understand it. */ path16 = g_utf8_to_utf16(path, -1, NULL, NULL, &error); if (error != NULL) { alertpanel_error(_("Could not convert file path to UTF-16:\n\n%s"), error->message); debug_print("file path '%s' conversion to UTF-16 failed\n", path); g_error_free(error); g_free(filename16); return NULL; } /* Chooser dialog title needs to be UTF-16 as well. */ title16 = g_utf8_to_utf16(title, -1, NULL, NULL, &error); if (error != NULL) { debug_print("dialog title '%s' conversion to UTF-16 failed\n", title); g_error_free(error); } o.lStructSize = sizeof(OPENFILENAME); if (focus_window != NULL) o.hwndOwner = GDK_WINDOW_HWND(gtk_widget_get_window(focus_window)); else o.hwndOwner = NULL; o.lpstrFilter = NULL; o.lpstrCustomFilter = NULL; o.lpstrFile = g_malloc0(MAXPATHLEN); if (path16 != NULL) memcpy(o.lpstrFile, filename16, conv_items * sizeof(gunichar2)); o.nMaxFile = MAXPATHLEN; o.lpstrFileTitle = NULL; o.lpstrInitialDir = path16; o.lpstrTitle = title16; o.Flags = OFN_LONGNAMES | OFN_EXPLORER; ctx = g_new0(WinChooserCtx, 1); ctx->data = &o; ctx->return_value = FALSE; ctx->done = FALSE; #ifdef USE_PTHREAD if (pthread_create(&pt, PTHREAD_CREATE_JOINABLE, threaded_GetSaveFileName, (void *)ctx) != 0) { debug_print("Couldn't run in a thread, continuing unthreaded.\n"); threaded_GetSaveFileName(ctx); } else { while (!ctx->done) { claws_do_idle(); } pthread_join(pt, NULL); } ret = ctx->return_value; #else debug_print("No threads available, continuing unthreaded.\n"); ret = GetSaveFileName(&o); #endif g_free(filename16); g_free(path16); g_free(title16); g_free(ctx); if (!ret) { g_free(o.lpstrFile); return NULL; } /* Now convert the returned file path back from UTF-16. */ str = g_utf16_to_utf8(o.lpstrFile, o.nMaxFile, NULL, NULL, &error); if (error != NULL) { alertpanel_error(_("Could not convert file path back to UTF-8:\n\n%s"), error->message); debug_print("returned file path conversion to UTF-8 failed\n"); g_error_free(error); } g_free(o.lpstrFile); return str; }
gchar *filesel_select_file_open_folder(const gchar *title, const gchar *path) { PIDLIST_ABSOLUTE pidl; gchar *str; gunichar2 *path16, *title16; glong conv_items; GError *error = NULL; WinChooserCtx *ctx; #ifdef USE_PTHREAD pthread_t pt; #endif /* Path needs to be converted to UTF-16, so that the native chooser * can understand it. */ path16 = g_utf8_to_utf16(path ? path : "", -1, NULL, &conv_items, &error); if (error != NULL) { alertpanel_error(_("Could not convert file path to UTF-16:\n\n%s"), error->message); debug_print("file path '%s' conversion to UTF-16 failed\n", path); g_error_free(error); return NULL; } /* Chooser dialog title needs to be UTF-16 as well. */ title16 = g_utf8_to_utf16(title ? title : "", -1, NULL, NULL, &error); if (error != NULL) { debug_print("dialog title '%s' conversion to UTF-16 failed\n", title); g_error_free(error); } if (focus_window != NULL) b.hwndOwner = GDK_WINDOW_HWND(gtk_widget_get_window(focus_window)); else b.hwndOwner = NULL; b.pszDisplayName = g_malloc(MAXPATHLEN); b.lpszTitle = title16; b.ulFlags = 0; b.pidlRoot = NULL; b.lpfn = _open_folder_callback; b.lParam = (LPARAM)path16; CoInitialize(NULL); ctx = g_new0(WinChooserCtx, 1); ctx->data = &b; ctx->done = FALSE; #ifdef USE_PTHREAD if (pthread_create(&pt, PTHREAD_CREATE_JOINABLE, threaded_SHBrowseForFolder, (void *)ctx) != 0) { debug_print("Couldn't run in a thread, continuing unthreaded.\n"); threaded_SHBrowseForFolder(ctx); } else { while (!ctx->done) { claws_do_idle(); } pthread_join(pt, NULL); } pidl = ctx->return_value_pidl; #else debug_print("No threads available, continuing unthreaded.\n"); pidl = SHBrowseForFolder(&b); #endif g_free(b.pszDisplayName); g_free(title16); g_free(path16); if (pidl == NULL) { CoUninitialize(); g_free(ctx); return NULL; } path16 = malloc(MAX_PATH); if (!SHGetPathFromIDList(pidl, path16)) { CoTaskMemFree(pidl); CoUninitialize(); g_free(path16); g_free(ctx); return NULL; } /* Now convert the returned file path back from UTF-16. */ /* Unfortunately, there is no field in BROWSEINFO struct to indicate * actual length of string in pszDisplayName, so we have to assume * the string is null-terminated. */ str = g_utf16_to_utf8(path16, -1, NULL, NULL, &error); if (error != NULL) { alertpanel_error(_("Could not convert file path back to UTF-8:\n\n%s"), error->message); debug_print("returned file path conversion to UTF-8 failed\n"); g_error_free(error); } CoTaskMemFree(pidl); CoUninitialize(); g_free(ctx); g_free(path16); return str; }
/* This function handles calling GetOpenFilename(), using * global static variable o. * It expects o.lpstrFile to point to an already allocated buffer, * of size at least MAXPATHLEN. */ static const gboolean _file_open_dialog(const gchar *path, const gchar *title, const gchar *filter, const gboolean multi) { gboolean ret; gunichar2 *path16 = NULL; gunichar2 *title16 = NULL; gunichar2 *filter16 = NULL; gunichar2 *win_filter16 = NULL; glong conv_items, sz; GError *error = NULL; WinChooserCtx *ctx; #ifdef USE_PTHREAD pthread_t pt; #endif /* Path needs to be converted to UTF-16, so that the native chooser * can understand it. */ path16 = g_utf8_to_utf16(path ? path : "", -1, NULL, NULL, &error); if (error != NULL) { alertpanel_error(_("Could not convert file path to UTF-16:\n\n%s"), error->message); debug_print("file path '%s' conversion to UTF-16 failed\n", path); g_error_free(error); error = NULL; return FALSE; } /* Chooser dialog title needs to be UTF-16 as well. */ title16 = g_utf8_to_utf16(title ? title : "", -1, NULL, NULL, &error); if (error != NULL) { debug_print("dialog title '%s' conversion to UTF-16 failed\n", title); g_error_free(error); error = NULL; } o.lStructSize = sizeof(OPENFILENAME); if (focus_window != NULL) o.hwndOwner = GDK_WINDOW_HWND(gtk_widget_get_window(focus_window)); else o.hwndOwner = NULL; o.hInstance = NULL; o.lpstrFilter = NULL; o.lpstrCustomFilter = NULL; o.nFilterIndex = 0; o.nMaxFile = MAXPATHLEN; o.lpstrFileTitle = NULL; o.lpstrInitialDir = path16; o.lpstrTitle = title16; if (multi) o.Flags = OFN_LONGNAMES | OFN_EXPLORER | OFN_ALLOWMULTISELECT; else o.Flags = OFN_LONGNAMES | OFN_EXPLORER; if (filter != NULL && strlen(filter) > 0) { debug_print("Setting filter '%s'\n", filter); filter16 = g_utf8_to_utf16(filter, -1, NULL, &conv_items, &error); /* We're creating a UTF16 (2 bytes for each character) string: * "filter\0filter\0\0" * As g_utf8_to_utf16() will stop on first null byte, even if * we pass string length in its second argument, we have to * construct this string manually. * conv_items contains number of UTF16 characters of our filter. * Therefore we need enough bytes to store the filter string twice * and three null chars. */ sz = sizeof(gunichar2); win_filter16 = g_malloc0(conv_items*sz*2 + sz*3); memcpy(win_filter16, filter16, conv_items*sz); memcpy(win_filter16 + conv_items*sz + sz, filter16, conv_items*sz); g_free(filter16); if (error != NULL) { debug_print("dialog title '%s' conversion to UTF-16 failed\n", title); g_error_free(error); error = NULL; } o.lpstrFilter = (LPCTSTR)win_filter16; o.nFilterIndex = 1; } ctx = g_new0(WinChooserCtx, 1); ctx->data = &o; ctx->done = FALSE; #ifdef USE_PTHREAD if (pthread_create(&pt, PTHREAD_CREATE_JOINABLE, threaded_GetOpenFileName, (void *)ctx) != 0) { debug_print("Couldn't run in a thread, continuing unthreaded.\n"); threaded_GetOpenFileName(ctx); } else { while (!ctx->done) { claws_do_idle(); } pthread_join(pt, NULL); } ret = ctx->return_value; #else debug_print("No threads available, continuing unthreaded.\n"); ret = GetOpenFileName(&o); #endif g_free(win_filter16); if (path16 != NULL) { g_free(path16); } g_free(title16); g_free(ctx); return ret; }