static gboolean pgpinline_is_signed(MimeInfo *mimeinfo) { PrivacyDataPGP *data = NULL; const gchar *sig_indicator = "-----BEGIN PGP SIGNED MESSAGE-----"; gchar *textdata, *sigpos; cm_return_val_if_fail(mimeinfo != NULL, FALSE); if (procmime_mimeinfo_parent(mimeinfo) == NULL) return FALSE; /* not parent */ if (mimeinfo->type != MIMETYPE_TEXT && (mimeinfo->type != MIMETYPE_APPLICATION || g_ascii_strcasecmp(mimeinfo->subtype, "pgp"))) return FALSE; /* Seal the deal. This has to be text/plain through and through. */ if (mimeinfo->type == MIMETYPE_APPLICATION) { mimeinfo->type = MIMETYPE_TEXT; g_free(mimeinfo->subtype); mimeinfo->subtype = g_strdup("plain"); } if (mimeinfo->privacy != NULL) { data = (PrivacyDataPGP *) mimeinfo->privacy; if (data->done_sigtest) return data->is_signed; } textdata = get_part_as_string(mimeinfo); if (!textdata) return FALSE; if ((sigpos = strstr(textdata, sig_indicator)) == NULL) { g_free(textdata); return FALSE; } if (!(sigpos == textdata) && !(sigpos[-1] == '\n')) { g_free(textdata); return FALSE; } g_free(textdata); if (data == NULL) { data = pgpinline_new_privacydata(); mimeinfo->privacy = (PrivacyData *) data; } if (data != NULL) { data->done_sigtest = TRUE; data->is_signed = TRUE; } return TRUE; }
static gboolean pgpmime_is_signed(MimeInfo *mimeinfo) { MimeInfo *parent; MimeInfo *signature; const gchar *protocol; PrivacyDataPGP *data = NULL; cm_return_val_if_fail(mimeinfo != NULL, FALSE); if (mimeinfo->privacy != NULL) { data = (PrivacyDataPGP *) mimeinfo->privacy; if (data->done_sigtest) return data->is_signed; } /* check parent */ parent = procmime_mimeinfo_parent(mimeinfo); if (parent == NULL) return FALSE; if ((parent->type != MIMETYPE_MULTIPART) || g_ascii_strcasecmp(parent->subtype, "signed")) return FALSE; protocol = procmime_mimeinfo_get_parameter(parent, "protocol"); if ((protocol == NULL) || (g_ascii_strcasecmp(protocol, "application/pgp-signature"))) return FALSE; /* check if mimeinfo is the first child */ if (parent->node->children->data != mimeinfo) return FALSE; /* check signature */ signature = parent->node->children->next != NULL ? (MimeInfo *) parent->node->children->next->data : NULL; if (signature == NULL) return FALSE; if ((signature->type != MIMETYPE_APPLICATION) || (g_ascii_strcasecmp(signature->subtype, "pgp-signature"))) return FALSE; if (data == NULL) { data = pgpmime_new_privacydata(); mimeinfo->privacy = (PrivacyData *) data; } if (data != NULL) { data->done_sigtest = TRUE; data->is_signed = TRUE; } return TRUE; }
static gint decrypt(MimeInfo *mimeinfo, PrivacySystem *system) { MimeInfo *decryptedinfo, *parentinfo; gint childnumber; cm_return_val_if_fail(system->decrypt != NULL, -1); decryptedinfo = system->decrypt(mimeinfo); if (decryptedinfo == NULL) return -1; parentinfo = procmime_mimeinfo_parent(mimeinfo); childnumber = g_node_child_index(parentinfo->node, mimeinfo); procmime_mimeinfo_free_all(&mimeinfo); g_node_insert(parentinfo->node, childnumber, decryptedinfo->node); return 0; }
static gboolean pgpinline_is_encrypted(MimeInfo *mimeinfo) { const gchar *begin_indicator = "-----BEGIN PGP MESSAGE-----"; const gchar *end_indicator = "-----END PGP MESSAGE-----"; gchar *textdata; cm_return_val_if_fail(mimeinfo != NULL, FALSE); if (procmime_mimeinfo_parent(mimeinfo) == NULL) return FALSE; /* not parent */ if (mimeinfo->type != MIMETYPE_TEXT && (mimeinfo->type != MIMETYPE_APPLICATION || g_ascii_strcasecmp(mimeinfo->subtype, "pgp"))) return FALSE; /* Seal the deal. This has to be text/plain through and through. */ if (mimeinfo->type == MIMETYPE_APPLICATION) { mimeinfo->type = MIMETYPE_TEXT; g_free(mimeinfo->subtype); mimeinfo->subtype = g_strdup("plain"); } textdata = get_part_as_string(mimeinfo); if (!textdata) return FALSE; if (!pgp_locate_armor_header(textdata, begin_indicator)) { g_free(textdata); return FALSE; } if (!pgp_locate_armor_header(textdata, end_indicator)) { g_free(textdata); return FALSE; } g_free(textdata); return TRUE; }
static void update_signature_info(MimeView *mimeview, MimeInfo *selected) { MimeInfo *siginfo; g_return_if_fail(mimeview != NULL); g_return_if_fail(selected != NULL); siginfo = selected; while (siginfo != NULL) { if (privacy_mimeinfo_is_signed(siginfo)) break; siginfo = procmime_mimeinfo_parent(siginfo); } mimeview->siginfo = siginfo; if (siginfo == NULL) { noticeview_hide(mimeview->siginfoview); return; } update_signature_noticeview(mimeview, siginfo); noticeview_show(mimeview->siginfoview); }
static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo) { MimeInfo *decinfo, *parseinfo; gpgme_data_t cipher, plain; FILE *dstfp; gchar *fname; gchar *textdata = NULL; static gint id = 0; const gchar *src_codeset = NULL; gpgme_verify_result_t sigstat = 0; PrivacyDataPGP *data = NULL; gpgme_ctx_t ctx; gchar *chars; size_t len; const gchar *begin_indicator = "-----BEGIN PGP MESSAGE-----"; const gchar *end_indicator = "-----END PGP MESSAGE-----"; gchar *pos; if (gpgme_new(&ctx) != GPG_ERR_NO_ERROR) return NULL; gpgme_set_textmode(ctx, 1); gpgme_set_armor(ctx, 1); cm_return_val_if_fail(mimeinfo != NULL, NULL); cm_return_val_if_fail(pgpinline_is_encrypted(mimeinfo), NULL); if (procmime_mimeinfo_parent(mimeinfo) == NULL || mimeinfo->type != MIMETYPE_TEXT) { gpgme_release(ctx); privacy_set_error(_("Couldn't parse mime part.")); return NULL; } textdata = get_part_as_string(mimeinfo); if (!textdata) { gpgme_release(ctx); privacy_set_error(_("Couldn't get text data.")); return NULL; } debug_print("decrypting '%s'\n", textdata); gpgme_data_new_from_mem(&cipher, textdata, (size_t)strlen(textdata), 1); plain = sgpgme_decrypt_verify(cipher, &sigstat, ctx); if (sigstat && !sigstat->signatures) sigstat = NULL; gpgme_data_release(cipher); if (plain == NULL) { gpgme_release(ctx); return NULL; } fname = g_strdup_printf("%s%cplaintext.%08x", get_mime_tmp_dir(), G_DIR_SEPARATOR, ++id); if ((dstfp = g_fopen(fname, "wb")) == NULL) { FILE_OP_ERROR(fname, "fopen"); privacy_set_error(_("Couldn't open decrypted file %s"), fname); g_free(fname); gpgme_data_release(plain); gpgme_release(ctx); return NULL; } src_codeset = procmime_mimeinfo_get_parameter(mimeinfo, "charset"); if (src_codeset == NULL) src_codeset = CS_ISO_8859_1; if (fprintf(dstfp, "MIME-Version: 1.0\r\n" "Content-Type: text/plain; charset=%s\r\n" "Content-Transfer-Encoding: 8bit\r\n" "\r\n", src_codeset) < 0) { FILE_OP_ERROR(fname, "fprintf"); privacy_set_error(_("Couldn't write to decrypted file %s"), fname); goto FILE_ERROR; } /* Store any part before encrypted text */ pos = pgp_locate_armor_header(textdata, begin_indicator); if (pos != NULL && (pos - textdata) > 0) { if (fwrite(textdata, 1, pos - textdata, dstfp) < pos - textdata) { FILE_OP_ERROR(fname, "fwrite"); privacy_set_error(_("Couldn't write to decrypted file %s"), fname); goto FILE_ERROR; } } if (fwrite(_("\n--- Start of PGP/Inline encrypted data ---\n"), 1, strlen(_("\n--- Start of PGP/Inline encrypted data ---\n")), dstfp) < strlen(_("\n--- Start of PGP/Inline encrypted data ---\n"))) { FILE_OP_ERROR(fname, "fwrite"); privacy_set_error(_("Couldn't write to decrypted file %s"), fname); goto FILE_ERROR; } chars = sgpgme_data_release_and_get_mem(plain, &len); if (len > 0) { if (fwrite(chars, 1, len, dstfp) < len) { FILE_OP_ERROR(fname, "fwrite"); g_free(chars); privacy_set_error(_("Couldn't write to decrypted file %s"), fname); goto FILE_ERROR; } } g_free(chars); /* Store any part after encrypted text */ if (fwrite(_("--- End of PGP/Inline encrypted data ---\n"), 1, strlen(_("--- End of PGP/Inline encrypted data ---\n")), dstfp) < strlen(_("--- End of PGP/Inline encrypted data ---\n"))) { FILE_OP_ERROR(fname, "fwrite"); privacy_set_error(_("Couldn't write to decrypted file %s"), fname); goto FILE_ERROR; } if (pos != NULL) { pos = pgp_locate_armor_header(pos, end_indicator); if (pos != NULL && *pos != '\0') { pos += strlen(end_indicator); if (fwrite(pos, 1, strlen(pos), dstfp) < strlen(pos)) { FILE_OP_ERROR(fname, "fwrite"); privacy_set_error(_("Couldn't write to decrypted file %s"), fname); goto FILE_ERROR; } } } if (fclose(dstfp) == EOF) { FILE_OP_ERROR(fname, "fclose"); privacy_set_error(_("Couldn't close decrypted file %s"), fname); g_free(fname); gpgme_data_release(plain); gpgme_release(ctx); return NULL; } parseinfo = procmime_scan_file(fname); g_free(fname); if (parseinfo == NULL) { gpgme_release(ctx); privacy_set_error(_("Couldn't scan decrypted file.")); return NULL; } decinfo = g_node_first_child(parseinfo->node) != NULL ? g_node_first_child(parseinfo->node)->data : NULL; if (decinfo == NULL) { gpgme_release(ctx); privacy_set_error(_("Couldn't scan decrypted file parts.")); return NULL; } g_node_unlink(decinfo->node); procmime_mimeinfo_free_all(parseinfo); decinfo->tmp = TRUE; if (sigstat != GPGME_SIG_STAT_NONE) { if (decinfo->privacy != NULL) { data = (PrivacyDataPGP *) decinfo->privacy; } else { data = pgpinline_new_privacydata(); decinfo->privacy = (PrivacyData *) data; } if (data != NULL) { data->done_sigtest = TRUE; data->is_signed = TRUE; data->sigstatus = sigstat; if (data->ctx) gpgme_release(data->ctx); data->ctx = ctx; } } else gpgme_release(ctx); return decinfo; FILE_ERROR: fclose(dstfp); g_free(fname); gpgme_data_release(plain); gpgme_release(ctx); return NULL; }
static gint pgpinline_check_signature(MimeInfo *mimeinfo) { PrivacyDataPGP *data = NULL; gchar *textdata = NULL, *tmp = NULL; gpgme_data_t plain = NULL, cipher = NULL; gpgme_error_t err; cm_return_val_if_fail(mimeinfo != NULL, 0); if (procmime_mimeinfo_parent(mimeinfo) == NULL) { privacy_set_error(_("Incorrect part")); return 0; /* not parent */ } if (mimeinfo->type != MIMETYPE_TEXT) { privacy_set_error(_("Not a text part")); debug_print("type %d\n", mimeinfo->type); return 0; } cm_return_val_if_fail(mimeinfo->privacy != NULL, 0); data = (PrivacyDataPGP *) mimeinfo->privacy; textdata = get_part_as_string(mimeinfo); if (!textdata) { g_free(textdata); privacy_set_error(_("Couldn't get text data.")); return 0; } /* gtk2: convert back from utf8 */ tmp = conv_codeset_strdup(textdata, CS_UTF_8, procmime_mimeinfo_get_parameter(mimeinfo, "charset")); if (!tmp) { tmp = conv_codeset_strdup(textdata, CS_UTF_8, conv_get_locale_charset_str_no_utf8()); } if (!tmp) { g_warning("Can't convert charset to anything sane"); tmp = conv_codeset_strdup(textdata, CS_UTF_8, CS_US_ASCII); } g_free(textdata); if (!tmp) { privacy_set_error(_("Couldn't convert text data to any sane charset.")); return 0; } textdata = g_strdup(tmp); g_free(tmp); if ((err = gpgme_new(&data->ctx)) != GPG_ERR_NO_ERROR) { debug_print(("Couldn't initialize GPG context, %s"), gpgme_strerror(err)); privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err)); g_free(textdata); return 0; } gpgme_set_textmode(data->ctx, 1); gpgme_set_armor(data->ctx, 1); gpgme_data_new_from_mem(&plain, textdata, (size_t)strlen(textdata), 1); gpgme_data_new(&cipher); data->sigstatus = sgpgme_verify_signature(data->ctx, plain, NULL, cipher); gpgme_data_release(plain); gpgme_data_release(cipher); g_free(textdata); return 0; }
static void icon_list_append_icon (MimeView *mimeview, MimeInfo *mimeinfo) { GtkWidget *pixmap; GtkWidget *vbox; GtkWidget *button; gchar *tip; gchar *tiptmp; const gchar *desc = NULL; gchar *sigshort = NULL; gchar *content_type; StockPixmap stockp; MimeInfo *partinfo; MimeInfo *siginfo = NULL; MimeInfo *encrypted = NULL; vbox = mimeview->icon_vbox; mimeview->icon_count++; button = gtk_toggle_button_new(); gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); gtk_object_set_data(GTK_OBJECT(button), "icon_number", GINT_TO_POINTER(mimeview->icon_count)); gtk_object_set_data(GTK_OBJECT(button), "partinfo", mimeinfo); switch (mimeinfo->type) { case MIMETYPE_TEXT: if (mimeinfo->subtype && !g_strcasecmp(mimeinfo->subtype, "html")) stockp = STOCK_PIXMAP_MIME_TEXT_HTML; else if (mimeinfo->subtype && !g_strcasecmp(mimeinfo->subtype, "enriched")) stockp = STOCK_PIXMAP_MIME_TEXT_ENRICHED; else stockp = STOCK_PIXMAP_MIME_TEXT_PLAIN; break; case MIMETYPE_MESSAGE: stockp = STOCK_PIXMAP_MIME_MESSAGE; break; case MIMETYPE_APPLICATION: stockp = STOCK_PIXMAP_MIME_APPLICATION; break; case MIMETYPE_IMAGE: stockp = STOCK_PIXMAP_MIME_IMAGE; break; case MIMETYPE_AUDIO: stockp = STOCK_PIXMAP_MIME_AUDIO; break; default: stockp = STOCK_PIXMAP_MIME_UNKNOWN; break; } partinfo = mimeinfo; while (partinfo != NULL) { if (privacy_mimeinfo_is_signed(partinfo)) { siginfo = partinfo; break; } if (privacy_mimeinfo_is_encrypted(partinfo)) { encrypted = partinfo; break; } partinfo = procmime_mimeinfo_parent(partinfo); } if (siginfo != NULL) { switch (privacy_mimeinfo_get_sig_status(siginfo)) { case SIGNATURE_UNCHECKED: case SIGNATURE_CHECK_FAILED: pixmap = stock_pixmap_widget_with_overlay(mimeview->mainwin->window, stockp, STOCK_PIXMAP_PRIVACY_EMBLEM_SIGNED, OVERLAY_BOTTOM_RIGHT, 6, 3); break; case SIGNATURE_OK: pixmap = stock_pixmap_widget_with_overlay(mimeview->mainwin->window, stockp, STOCK_PIXMAP_PRIVACY_EMBLEM_PASSED, OVERLAY_BOTTOM_RIGHT, 6, 3); break; case SIGNATURE_WARN: pixmap = stock_pixmap_widget_with_overlay(mimeview->mainwin->window, stockp, STOCK_PIXMAP_PRIVACY_EMBLEM_WARN, OVERLAY_BOTTOM_RIGHT, 6, 3); break; case SIGNATURE_INVALID: pixmap = stock_pixmap_widget_with_overlay(mimeview->mainwin->window, stockp, STOCK_PIXMAP_PRIVACY_EMBLEM_FAILED, OVERLAY_BOTTOM_RIGHT, 6, 3); break; } sigshort = privacy_mimeinfo_sig_info_short(siginfo); } else if (encrypted != NULL) { pixmap = stock_pixmap_widget_with_overlay(mimeview->mainwin->window, stockp, STOCK_PIXMAP_PRIVACY_EMBLEM_ENCRYPTED, OVERLAY_BOTTOM_RIGHT, 6, 3); } else { pixmap = stock_pixmap_widget_with_overlay(mimeview->mainwin->window, stockp, 0, OVERLAY_NONE, 6, 3); } gtk_container_add(GTK_CONTAINER(button), pixmap); if (!desc) { if (prefs_common.attach_desc) desc = get_part_description(mimeinfo); else desc = get_part_name(mimeinfo); } content_type = procmime_get_content_type_str(mimeinfo->type, mimeinfo->subtype); tip = g_strjoin("\n", content_type, to_human_readable(mimeinfo->length), NULL); g_free(content_type); if (desc && *desc) { tiptmp = g_strjoin("\n", desc, tip, NULL); g_free(tip); tip = tiptmp; } if (sigshort && *sigshort) { tiptmp = g_strjoin("\n", tip, sigshort, NULL); g_free(tip); tip = tiptmp; } g_free(sigshort); gtk_tooltips_set_tip(mimeview->tooltips, button, tip, NULL); g_free(tip); gtk_widget_show_all(button); gtk_signal_connect(GTK_OBJECT(button), "button_release_event", GTK_SIGNAL_FUNC(icon_clicked_cb), mimeview); gtk_signal_connect(GTK_OBJECT(button), "key_press_event", GTK_SIGNAL_FUNC(icon_key_pressed), mimeview); gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0); }
static gint pgpmime_check_signature(MimeInfo *mimeinfo) { PrivacyDataPGP *data; MimeInfo *parent, *signature; FILE *fp; gchar *boundary; gchar *textstr; gpgme_data_t sigdata = NULL, textdata = NULL; gpgme_error_t err; cm_return_val_if_fail(mimeinfo != NULL, -1); cm_return_val_if_fail(mimeinfo->privacy != NULL, -1); data = (PrivacyDataPGP *) mimeinfo->privacy; if ((err = gpgme_new(&data->ctx)) != GPG_ERR_NO_ERROR) { debug_print(("Couldn't initialize GPG context, %s\n"), gpgme_strerror(err)); privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err)); return 0; } debug_print("Checking PGP/MIME signature\n"); err = gpgme_set_protocol(data->ctx, GPGME_PROTOCOL_OpenPGP); if (err) { debug_print ("gpgme_set_protocol failed: %s\n", gpgme_strerror (err)); } parent = procmime_mimeinfo_parent(mimeinfo); fp = claws_fopen(parent->data.filename, "rb"); cm_return_val_if_fail(fp != NULL, SIGNATURE_INVALID); boundary = g_hash_table_lookup(parent->typeparameters, "boundary"); if (!boundary) { privacy_set_error(_("Signature boundary not found.")); claws_fclose(fp); return 0; } textstr = get_canonical_content(fp, boundary); err = gpgme_data_new_from_mem(&textdata, textstr, (size_t)strlen(textstr), 0); if (err) { debug_print ("gpgme_data_new_from_mem failed: %s\n", gpgme_strerror (err)); } signature = (MimeInfo *) mimeinfo->node->next->data; sigdata = sgpgme_data_from_mimeinfo(signature); err = 0; if (signature->encoding_type == ENC_BASE64) { err = gpgme_data_set_encoding (sigdata, GPGME_DATA_ENCODING_BASE64); } if (err) { debug_print ("gpgme_data_set_encoding failed: %s\n", gpgme_strerror (err)); } data->sigstatus = sgpgme_verify_signature (data->ctx, sigdata, textdata, NULL); gpgme_data_release(sigdata); gpgme_data_release(textdata); g_free(textstr); claws_fclose(fp); return 0; }