diff --git a/mms-engine/main.c b/mms-engine/main.c index dd28290..42ebc3f 100644 --- a/mms-engine/main.c +++ b/mms-engine/main.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2013-2020 Jolla Ltd. * Copyright (C) 2013-2020 Slava Monich - * Copyright (C) 2019 Open Mobile Platform LLC. + * Copyright (C) 2020 Open Mobile Platform LLC. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -403,18 +403,21 @@ mms_app_parse_options( gboolean disable_dbus_log = FALSE; gint size_limit_kb = -1; gdouble megapixels = -1; + MMSConfig* config = &opt->global.config; + MMSSettingsSimDataCopy* settings = &opt->settings; + char* root_dir_help = g_strdup_printf( "Root directory for MMS files [%s]", - opt->global.config.root_dir); + config->root_dir); char* retry_secs_help = g_strdup_printf( "Retry period in seconds [%d]", - opt->global.config.retry_secs); + config->retry_secs); char* network_idle_secs_help = g_strdup_printf( "Network inactivity timeout in seconds [%d]", - opt->global.config.network_idle_secs); + config->network_idle_secs); char* idle_secs_help = g_strdup_printf( "Service inactivity timeout in seconds [%d]", - opt->global.config.idle_secs); + config->idle_secs); char* description = gutil_log_description(NULL, 0); GOptionContext* options; @@ -428,12 +431,12 @@ mms_app_parse_options( { "root-dir", 'd', 0, G_OPTION_ARG_FILENAME, &root_dir, root_dir_help, "DIR" }, { "retry-secs", 'r', 0, G_OPTION_ARG_INT, - &opt->global.config.retry_secs, retry_secs_help, "SEC" }, + &config->retry_secs, retry_secs_help, "SEC" }, { "network-idle-secs", 'n', 0, G_OPTION_ARG_INT, - &opt->global.config.network_idle_secs, + &config->network_idle_secs, network_idle_secs_help, "SEC" }, { "idle-secs", 'i', 0, G_OPTION_ARG_INT, - &opt->global.config.idle_secs, idle_secs_help, "SEC" }, + &config->idle_secs, idle_secs_help, "SEC" }, { "size-limit", 's', 0, G_OPTION_ARG_INT, &size_limit_kb, "Maximum size for outgoing messages", "KB" }, { "pix-limit", 'p', 0, G_OPTION_ARG_DOUBLE, @@ -445,12 +448,15 @@ mms_app_parse_options( { "keep-running", 'k', 0, G_OPTION_ARG_NONE, &keep_running, "Keep running after everything is done", NULL }, { "keep-temp-files", 't', 0, G_OPTION_ARG_NONE, - &opt->global.config.keep_temp_files, + &config->keep_temp_files, "Don't delete temporary files", NULL }, + { "preserve-encoding", 'e', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, + &config->convert_to_utf8, + "Don't convert text parts to UTF-8", NULL }, { "attic", 'a', 0, G_OPTION_ARG_NONE, - &opt->global.config.attic_enabled, + &config->attic_enabled, "Store unrecognized push messages in the attic", NULL }, -#define OPT_VERBOSE_INDEX 13 +#define OPT_VERBOSE_INDEX 14 { "verbose", 'v', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, mms_app_option_verbose, "Be verbose (equivalent to -l=verbose)", NULL }, @@ -560,28 +566,28 @@ mms_app_parse_options( GINFO("Starting"); #endif if (size_limit_kb >= 0) { - opt->settings.data.size_limit = size_limit_kb * 1024; + settings->data.size_limit = size_limit_kb * 1024; opt->flags |= MMS_ENGINE_FLAG_OVERRIDE_SIZE_LIMIT; } if (megapixels >= 0) { - opt->settings.data.max_pixels = (int)(megapixels*1000)*1000; + settings->data.max_pixels = (int)(megapixels*1000)*1000; opt->flags |= MMS_ENGINE_FLAG_OVERRIDE_MAX_PIXELS; } if (ua) { - g_free(opt->settings.user_agent); - opt->settings.data.user_agent = opt->settings.user_agent = ua; + g_free(settings->user_agent); + settings->data.user_agent = settings->user_agent = ua; opt->flags |= MMS_ENGINE_FLAG_OVERRIDE_USER_AGENT; ua = NULL; } if (uaprof) { - g_free(opt->settings.uaprof); - opt->settings.data.uaprof = opt->settings.uaprof = uaprof; + g_free(settings->uaprof); + settings->data.uaprof = settings->uaprof = uaprof; opt->flags |= MMS_ENGINE_FLAG_OVERRIDE_UAPROF; uaprof = NULL; } if (root_dir) { g_free(opt->global.root_dir); - opt->global.config.root_dir = opt->global.root_dir = root_dir; + config->root_dir = opt->global.root_dir = root_dir; root_dir = NULL; } if (keep_running) opt->flags |= MMS_ENGINE_FLAG_KEEP_RUNNING; diff --git a/mms-lib/Makefile b/mms-lib/Makefile index 43107ab..c90313f 100644 --- a/mms-lib/Makefile +++ b/mms-lib/Makefile @@ -28,6 +28,7 @@ SRC = \ mms_attachment.c \ mms_attachment_image.c \ mms_attachment_jpeg.c \ + mms_attachment_text.c \ mms_codec.c \ mms_connection.c \ mms_connman.c \ diff --git a/mms-lib/include/mms_settings.h b/mms-lib/include/mms_settings.h index 35ed901..fe5fd64 100644 --- a/mms-lib/include/mms_settings.h +++ b/mms-lib/include/mms_settings.h @@ -1,7 +1,7 @@ /* - * Copyright (C) 2014-2019 Jolla Ltd. - * Copyright (C) 2014-2019 Slava Monich - * Copyright (C) 2019 Open Mobile Platform LLC. + * Copyright (C) 2014-2020 Jolla Ltd. + * Copyright (C) 2014-2020 Slava Monich + * Copyright (C) 2020 Open Mobile Platform LLC. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -13,8 +13,8 @@ * GNU General Public License for more details. */ -#ifndef JOLLA_MMS_SETTINGS_H -#define JOLLA_MMS_SETTINGS_H +#ifndef SAILFISH_MMS_SETTINGS_H +#define SAILFISH_MMS_SETTINGS_H #include "mms_lib_types.h" @@ -24,6 +24,7 @@ struct mms_config { int retry_secs; /* Retry timeout in seconds */ int network_idle_secs; /* Network inactivity timeout */ int idle_secs; /* Service inactivity timeout */ + gboolean convert_to_utf8; /* Convert text parts to UTF-8 */ gboolean keep_temp_files; /* Keep temporary files around */ gboolean attic_enabled; /* Keep unrecognized push message in attic */ }; @@ -145,7 +146,7 @@ mms_settings_sim_data_copy( #define mms_settings_sim_data_reset(data) \ mms_settings_sim_data_copy(data,NULL) -#endif /* JOLLA_MMS_SETTINGS_H */ +#endif /* SAILFISH_MMS_SETTINGS_H */ /* * Local Variables: diff --git a/mms-lib/mms-lib.pro b/mms-lib/mms-lib.pro index 299165b..ee573d2 100644 --- a/mms-lib/mms-lib.pro +++ b/mms-lib/mms-lib.pro @@ -28,6 +28,7 @@ SOURCES += \ src/mms_attachment.c \ src/mms_attachment_image.c \ src/mms_attachment_jpeg.c \ + src/mms_attachment_text.c \ src/mms_attachment_qt.cpp \ src/mms_codec.c \ src/mms_connection.c \ diff --git a/mms-lib/src/mms_attachment.c b/mms-lib/src/mms_attachment.c index 1e0cd28..e74f855 100644 --- a/mms-lib/src/mms_attachment.c +++ b/mms-lib/src/mms_attachment.c @@ -1,6 +1,7 @@ /* - * Copyright (C) 2013-2016 Jolla Ltd. - * Contact: Slava Monich + * Copyright (C) 2013-2020 Jolla Ltd. + * Copyright (C) 2013-2020 Slava Monich + * Copyright (C) 2020 Open Mobile Platform LLC. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -17,6 +18,8 @@ #include "mms_settings.h" #include "mms_codec.h" +#include "gutil_strv.h" + #ifdef HAVE_MAGIC # include #endif @@ -27,7 +30,6 @@ GLOG_MODULE_DEFINE("mms-attachment"); #define MMS_ATTACHMENT_DEFAULT_TYPE "application/octet-stream" -#define CONTENT_TYPE_PARAM_NAME "name" G_DEFINE_TYPE(MMSAttachment, mms_attachment, G_TYPE_OBJECT) @@ -58,8 +60,7 @@ mms_attachment_finalize( MMSAttachment* at = MMS_ATTACHMENT(object); GVERBOSE_("%p", at); if (at->map) g_mapped_file_unref(at->map); - if (!at->config->keep_temp_files && - !(at->flags & MMS_ATTACHMENT_KEEP_FILES)) { + if (!at->config->keep_temp_files) { char* dir = g_path_get_dirname(at->original_file); remove(at->original_file); rmdir(dir); @@ -201,6 +202,7 @@ mms_attachment_write_smil( return FALSE; } +static char* mms_attachment_guess_content_type( const char* path) @@ -239,6 +241,38 @@ mms_attachment_guess_content_type( return content_type; } +static +char* +mms_attachment_guess_text_encoding( + const char* path) +{ + char* encoding = NULL; + const char* detected = NULL; + +#ifdef HAVE_MAGIC + /* Use magic to determine mime type */ + magic_t magic = magic_open(MAGIC_MIME_ENCODING); + if (magic) { + if (magic_load(magic, NULL) == 0) { + detected = magic_file(magic, path); + } + } +#endif + + if (detected) { + GDEBUG("%s: detected %s", path, detected); + encoding = g_strdup(detected); + } else { + encoding = g_strdup(MMS_DEFAULT_CHARSET); + } + +#ifdef HAVE_MAGIC + if (magic) magic_close(magic); +#endif + + return encoding; +} + MMSAttachment* mms_attachment_new_smil( const MMSConfig* config, @@ -259,7 +293,8 @@ mms_attachment_new_smil( if (ok) { MMSAttachmentInfo ai; ai.file_name = path; - ai.content_type = SMIL_CONTENT_TYPE "; charset=utf-8"; + ai.content_type = SMIL_CONTENT_TYPE "; " + CONTENT_TYPE_PARAM_CHARSET "=" MMS_DEFAULT_CHARSET; ai.content_id = NULL; smil = mms_attachment_new(config, &ai, error); GASSERT(smil && (smil->flags & MMS_ATTACHMENT_SMIL)); @@ -290,30 +325,51 @@ mms_attachment_new( char* media_type = NULL; char* name = g_path_get_basename(path); char* content_type = NULL; - GType type; + GType type = MMS_TYPE_ATTACHMENT; MMSAttachment* at; - + MMSAttachmentClass* klass; + + /* + * We always need to provide charset for text attachments because + * operators may (and often do) want to convert those to their + * favorite charset, in which case they need to know the original + * one (some just blindly assume us-ascii and mess things up). + */ if (info->content_type && info->content_type[0]) { char** ct = mms_parse_http_content_type(info->content_type); if (ct) { char** ptr; gboolean append_name = TRUE; - if (!strcmp(ct[0], SMIL_CONTENT_TYPE)) { - flags |= MMS_ATTACHMENT_SMIL; - } + gboolean append_charset = g_str_has_prefix(ct[0], + MEDIA_TYPE_TEXT_PREFIX); + for (ptr = ct+1; *ptr; ptr+=2) { - if (!g_ascii_strcasecmp(ptr[0], CONTENT_TYPE_PARAM_NAME)) { + const char* p = ptr[0]; + + if (!g_ascii_strcasecmp(p, CONTENT_TYPE_PARAM_NAME)) { g_free(ptr[1]); ptr[1] = g_strdup(name); append_name = FALSE; + } else if (append_charset && !g_ascii_strcasecmp(p, + CONTENT_TYPE_PARAM_CHARSET)) { + /* Charset is provided by the caller */ + append_charset = FALSE; } } if (append_name) { - const guint len = g_strv_length(ct); - ct = g_renew(gchar*, ct, len+3); - ct[len] = g_strdup(CONTENT_TYPE_PARAM_NAME); - ct[len+1] = g_strdup(name); - ct[len+2] = NULL; + ct = gutil_strv_addv(ct, + CONTENT_TYPE_PARAM_NAME, name, + NULL); + } + if (append_charset) { + char* enc = mms_attachment_guess_text_encoding(path); + + if (enc) { + ct = gutil_strv_addv(ct, + CONTENT_TYPE_PARAM_CHARSET, enc, + NULL); + g_free(enc); + } } content_type = mms_unparse_http_content_type(ct); media_type = g_strdup(ct[0]); @@ -322,40 +378,37 @@ mms_attachment_new( } if (!content_type) { - const char* default_charset = "utf-8"; + char* detected = NULL; const char* charset = NULL; const char* ct[6]; int n = 0; media_type = mms_attachment_guess_content_type(path); - if (!strcmp(media_type, SMIL_CONTENT_TYPE)) { - flags |= MMS_ATTACHMENT_SMIL; - charset = default_charset; - } else { - if (g_str_has_prefix(media_type, MEDIA_TYPE_TEXT_PREFIX)) { - charset = default_charset; - } + if (g_str_has_prefix(media_type, MEDIA_TYPE_TEXT_PREFIX)) { + detected = mms_attachment_guess_text_encoding(path); + charset = detected; } ct[n++] = media_type; if (charset) { - ct[n++] = "charset"; + ct[n++] = CONTENT_TYPE_PARAM_CHARSET; ct[n++] = charset; } ct[n++] = CONTENT_TYPE_PARAM_NAME; ct[n++] = name; ct[n++] = NULL; content_type = mms_unparse_http_content_type((char**)ct); + g_free(detected); } - GDEBUG("%s: %s", path, content_type); - - if (!strcmp(media_type, "image/jpeg")) { + if (!strcmp(media_type, SMIL_CONTENT_TYPE)) { + flags |= MMS_ATTACHMENT_SMIL; + } else if (!strcmp(media_type, "image/jpeg")) { type = MMS_TYPE_ATTACHMENT_JPEG; } else if (g_str_has_prefix(media_type, MEDIA_TYPE_IMAGE_PREFIX)) { type = MMS_TYPE_ATTACHMENT_IMAGE; - } else { - type = MMS_TYPE_ATTACHMENT; + } else if (g_str_has_prefix(media_type, MEDIA_TYPE_TEXT_PREFIX)) { + type = MMS_TYPE_ATTACHMENT_TEXT; } at = g_object_new(type, NULL); @@ -369,8 +422,16 @@ mms_attachment_new( g_strdup(info->content_id) : g_strdup(at->content_location); + path = NULL; g_free(media_type); - return at; + klass = MMS_ATTACHMENT_GET_CLASS(at); + + if (!klass->fn_init || klass->fn_init(at)) { + GDEBUG("%s: %s", at->file_name, at->content_type); + return at; + } + /* Init failed */ + mms_attachment_unref(at); } g_free(path); } diff --git a/mms-lib/src/mms_attachment.h b/mms-lib/src/mms_attachment.h index 7d0a427..9946c84 100644 --- a/mms-lib/src/mms_attachment.h +++ b/mms-lib/src/mms_attachment.h @@ -1,5 +1,7 @@ /* - * Copyright (C) 2013-2014 Jolla Ltd. + * Copyright (C) 2013-2020 Jolla Ltd. + * Copyright (C) 2013-2020 Slava Monich + * Copyright (C) 2020 Open Mobile Platform LLC. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -12,8 +14,8 @@ * */ -#ifndef JOLLA_MMS_ATTACHMENT_H -#define JOLLA_MMS_ATTACHMENT_H +#ifndef SAILFISH_MMS_ATTACHMENT_H +#define SAILFISH_MMS_ATTACHMENT_H #include "mms_lib_types.h" @@ -30,13 +32,17 @@ struct _mms_attachment { unsigned int flags; /* Flags: */ #define MMS_ATTACHMENT_SMIL (0x01) -#define MMS_ATTACHMENT_KEEP_FILES (0x02) -#define MMS_ATTACHMENT_RESIZABLE (0x04) - +#define MMS_ATTACHMENT_RESIZABLE (0x02) }; +#define CONTENT_TYPE_PARAM_NAME "name" +#define CONTENT_TYPE_PARAM_CHARSET "charset" +#define MMS_DEFAULT_CHARSET "utf-8" + typedef struct mms_attachment_class { GObjectClass parent; + gboolean (*fn_init)( + MMSAttachment* attachment); void (*fn_reset)( MMSAttachment* attachment); gboolean (*fn_resize)( @@ -45,9 +51,11 @@ typedef struct mms_attachment_class { } MMSAttachmentClass; GType mms_attachment_get_type(void); +GType mms_attachment_text_get_type(void); GType mms_attachment_image_get_type(void); GType mms_attachment_jpeg_get_type(void); #define MMS_TYPE_ATTACHMENT (mms_attachment_get_type()) +#define MMS_TYPE_ATTACHMENT_TEXT (mms_attachment_text_get_type()) #define MMS_TYPE_ATTACHMENT_IMAGE (mms_attachment_image_get_type()) #define MMS_TYPE_ATTACHMENT_JPEG (mms_attachment_jpeg_get_type()) @@ -77,16 +85,12 @@ void mms_attachment_reset( MMSAttachment* attachment); -char* -mms_attachment_guess_content_type( - const char* path); - gboolean mms_attachment_resize( MMSAttachment* attachment, const MMSSettingsSimData* settings); -#endif /* JOLLA_MMS_ATTACHMENT_H */ +#endif /* SAILFISH_MMS_ATTACHMENT_H */ /* * Local Variables: diff --git a/mms-lib/src/mms_attachment_image.c b/mms-lib/src/mms_attachment_image.c index 766b3c6..2920b3b 100644 --- a/mms-lib/src/mms_attachment_image.c +++ b/mms-lib/src/mms_attachment_image.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2013-2020 Jolla Ltd. * Copyright (C) 2013-2020 Slava Monich + * Copyright (C) 2020 Open Mobile Platform LLC. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -54,18 +55,12 @@ const char* mms_attachment_image_prepare_filename( MMSAttachmentImage* image) { + char* original = image->attachment.original_file; if (image->resized) { remove(image->resized); - image->attachment.file_name = image->attachment.original_file; + image->attachment.file_name = original; } else { - char* dir = g_path_get_dirname(image->attachment.original_file); - char* fname = g_path_get_basename(image->attachment.original_file); - char* subdir = g_build_filename(dir, MMS_RESIZE_DIR, NULL); - g_mkdir_with_parents(subdir, MMS_DIR_PERM); - image->resized = g_build_filename(subdir, fname, NULL); - g_free(dir); - g_free(fname); - g_free(subdir); + image->resized = mms_prepare_filename(original, MMS_CONVERT_DIR); } return image->resized; } @@ -300,8 +295,7 @@ mms_attachment_image_finalize( GObject* object) { MMSAttachmentImage* image = MMS_ATTACHMENT_IMAGE(object); - if (!image->attachment.config->keep_temp_files && - !(image->attachment.flags & MMS_ATTACHMENT_KEEP_FILES)) { + if (!image->attachment.config->keep_temp_files) { mms_remove_file_and_dir(image->resized); } g_free(image->resized); diff --git a/mms-lib/src/mms_attachment_text.c b/mms-lib/src/mms_attachment_text.c new file mode 100644 index 0000000..7d788a9 --- /dev/null +++ b/mms-lib/src/mms_attachment_text.c @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2020 Jolla Ltd. + * Copyright (C) 2020 Slava Monich + * Copyright (C) 2020 Open Mobile Platform LLC. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "mms_attachment.h" +#include "mms_settings.h" +#include "mms_codec.h" +#include "mms_file_util.h" + +#include + +/* Logging */ +#define GLOG_MODULE_NAME mms_attachment_log +#include + +typedef struct mms_attachment_text { + MMSAttachment attachment; + char* utf8file; +} MMSAttachmentText; + +typedef MMSAttachmentClass MMSAttachmentTextClass; +G_DEFINE_TYPE(MMSAttachmentText, mms_attachment_text, MMS_TYPE_ATTACHMENT) +#define MMS_ATTACHMENT_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + MMS_TYPE_ATTACHMENT_TEXT, MMSAttachmentText)) + +static +void +mms_attachment_text_convert_to_utf8( + MMSAttachment* at) +{ + MMSAttachmentText* self = MMS_ATTACHMENT_TEXT(at); + char** ct = mms_parse_http_content_type(at->content_type); + const int n = gutil_strv_length(ct); + int i, cs_pos = 0; + /* Find current charset */ + for (i = 1; i < n; i += 2) { + if (!g_ascii_strcasecmp(ct[i], CONTENT_TYPE_PARAM_CHARSET)) { + cs_pos = i; + break; + } + } + if (cs_pos > 0) { + /* Check if it's already UTF-8 or US-ASCII */ + const char* charset = ct[cs_pos + 1]; + if (g_ascii_strcasecmp(charset, MMS_DEFAULT_CHARSET) && + g_ascii_strcasecmp(charset, "US=ASCII")) { + /* Conversion is needed */ + GError* err = NULL; + gsize utf8size; + const char* in = at->original_file; + const gchar* indata = g_mapped_file_get_contents(at->map); + const gsize insize = g_mapped_file_get_length(at->map); + gchar* utf8 = g_convert(indata, insize, MMS_DEFAULT_CHARSET, + charset, NULL, &utf8size, &err); + if (utf8) { + char* out = mms_prepare_filename(in, MMS_CONVERT_DIR); + if (g_file_set_contents(out, utf8, utf8size, &err)) { + GMappedFile* map = g_mapped_file_new(out, FALSE, &err); + if (map) { + GDEBUG("%s (%d bytes) -> %s (%d bytes)", in, + (int)insize, out, (int)utf8size); + /* Substitute file mapping */ + g_mapped_file_unref(at->map); + at->file_name = self->utf8file = out; + at->map = map; + out = NULL; + /* Update content type header */ + g_free(at->content_type); + g_free(ct[cs_pos + 1]); + ct[cs_pos + 1] = g_strdup(MMS_DEFAULT_CHARSET); + at->content_type = mms_unparse_http_content_type(ct); + } else { + GERR("Failed to map %s: %s", out, GERRMSG(err)); + g_error_free(err); + } + } else { + GERR("Failed to write %s: %s", out, GERRMSG(err)); + g_error_free(err); + } + g_free(out); + g_free(utf8); + } else { + GERR("Failed to convert %s: %s", in, GERRMSG(err)); + g_error_free(err); + } + } else { + GDEBUG("%s: no conversion required", at->file_name); + } + } + g_strfreev(ct); +} + +static +gboolean +mms_attachment_text_init_attachment( + MMSAttachment* at) +{ + if (at->config->convert_to_utf8) { + mms_attachment_text_convert_to_utf8(at); + } else { + GDEBUG("%s: preserving charset", at->file_name); + } + return TRUE; +} + +static +void +mms_attachment_text_finalize( + GObject* object) +{ + MMSAttachmentText* self = MMS_ATTACHMENT_TEXT(object); + if (!self->attachment.config->keep_temp_files) { + mms_remove_file_and_dir(self->utf8file); + } + g_free(self->utf8file); + G_OBJECT_CLASS(mms_attachment_text_parent_class)->finalize(object); +} + +static +void +mms_attachment_text_class_init( + MMSAttachmentTextClass* klass) +{ + klass->fn_init = mms_attachment_text_init_attachment; + G_OBJECT_CLASS(klass)->finalize = mms_attachment_text_finalize; +} + +static +void +mms_attachment_text_init( + MMSAttachmentText* self) +{ +} + +/* + * Local Variables: + * mode: C + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/mms-lib/src/mms_file_util.c b/mms-lib/src/mms_file_util.c index 91f6744..a016fd0 100644 --- a/mms-lib/src/mms_file_util.c +++ b/mms-lib/src/mms_file_util.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2013-2020 Jolla Ltd. * Copyright (C) 2013-2020 Slava Monich + * Copyright (C) 2020 Open Mobile Platform LLC. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -92,6 +93,28 @@ mms_remove_file_and_dir( } } +/** + * Builds a file name with the same basename but in the subdirectory + * relative to the original file. Creates the subdirectory. + */ +char* +mms_prepare_filename( + const char* file, + const char* subdir) +{ + char* dir = g_path_get_dirname(file); + char* fname = g_path_get_basename(file); + char* newdir = g_build_filename(dir, subdir, NULL); + char* out; + + g_mkdir_with_parents(newdir, MMS_DIR_PERM); + out = g_build_filename(newdir, fname, NULL); + g_free(dir); + g_free(fname); + g_free(newdir); + return out; +} + /** * Creates a file in the specified directory. Creates the directory if * it doesn't exist. If file already exists, truncates it. Returns file diff --git a/mms-lib/src/mms_file_util.h b/mms-lib/src/mms_file_util.h index 62d2e41..990f3f9 100644 --- a/mms-lib/src/mms_file_util.h +++ b/mms-lib/src/mms_file_util.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2013-2020 Jolla Ltd. * Copyright (C) 2013-2020 Slava Monich + * Copyright (C) 2020 Open Mobile Platform LLC. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -29,7 +30,7 @@ #define MMS_MESSAGE_DIR "msg" #define MMS_PARTS_DIR "parts" #define MMS_ENCODE_DIR "encode" -#define MMS_RESIZE_DIR "resize" +#define MMS_CONVERT_DIR "convert" #define MMS_NOTIFICATION_IND_FILE "m-notification.ind" #define MMS_NOTIFYRESP_IND_FILE "m-notifyresp.ind" @@ -50,12 +51,19 @@ void mms_remove_file_and_dir( const char* file); +char* +mms_prepare_filename( + const char* file, + const char* subdir) + G_GNUC_WARN_UNUSED_RESULT; + int mms_create_file( const char* dir, const char* fname, char** path, - GError** error); + GError** error) + G_GNUC_WARN_UNUSED_RESULT; gboolean mms_write_file( diff --git a/mms-lib/src/mms_lib_util.c b/mms-lib/src/mms_lib_util.c index 6bbb13f..9d80cd8 100644 --- a/mms-lib/src/mms_lib_util.c +++ b/mms-lib/src/mms_lib_util.c @@ -1,6 +1,7 @@ /* - * Copyright (C) 2013-2018 Jolla Ltd. - * Copyright (C) 2013-2018 Slava Monich + * Copyright (C) 2013-2020 Jolla Ltd. + * Copyright (C) 2013-2020 Slava Monich + * Copyright (C) 2020 Open Mobile Platform LLC. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -70,6 +71,7 @@ mms_lib_default_config( config->idle_secs = MMS_CONFIG_DEFAULT_IDLE_SECS; config->keep_temp_files = FALSE; config->attic_enabled = FALSE; + config->convert_to_utf8 = TRUE; } /* diff --git a/mms-lib/src/mms_settings.c b/mms-lib/src/mms_settings.c index 905a9f3..b2c47ac 100644 --- a/mms-lib/src/mms_settings.c +++ b/mms-lib/src/mms_settings.c @@ -1,7 +1,7 @@ /* - * Copyright (C) 2014-2019 Jolla Ltd. - * Copyright (C) 2014-2019 Slava Monich - * Copyright (C) 2019 Open Mobile Platform LLC. + * Copyright (C) 2014-2020 Jolla Ltd. + * Copyright (C) 2014-2020 Slava Monich + * Copyright (C) 2020 Open Mobile Platform LLC. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -26,6 +26,7 @@ GLOG_MODULE_DEFINE("mms-settings"); #define SETTINGS_GLOBAL_KEY_RETRY_SEC "RetryDelay" #define SETTINGS_GLOBAL_KEY_NETWORK_IDLE_SEC "NetworkIdleTimeout" #define SETTINGS_GLOBAL_KEY_IDLE_SEC "IdleTimeout" +#define SETTINGS_GLOBAL_KEY_COVERT_TO_UTF8 "ConvertToUTF8" #define SETTINGS_DEFAULTS_GROUP "Defaults" #define SETTINGS_DEFAULTS_KEY_USER_AGENT "UserAgent" @@ -104,6 +105,24 @@ mms_settings_parse_uint( } } +static +void +mms_settings_parse_bool( + GKeyFile* file, + const char* group, + const char* key, + gboolean* out) +{ + GError* error = NULL; + gboolean value = g_key_file_get_boolean(file, group, key, &error); + + if (error) { + g_error_free(error); + } else { + *out = value; + } +} + static void mms_settings_parse_global_config( @@ -133,6 +152,10 @@ mms_settings_parse_global_config( mms_settings_parse_int(file, group, SETTINGS_GLOBAL_KEY_IDLE_SEC, &config->idle_secs, 0); + + mms_settings_parse_bool(file, group, + SETTINGS_GLOBAL_KEY_COVERT_TO_UTF8, + &config->convert_to_utf8); } static diff --git a/mms-lib/src/mms_task_encode.c b/mms-lib/src/mms_task_encode.c index 332d4f0..aea4ba4 100644 --- a/mms-lib/src/mms_task_encode.c +++ b/mms-lib/src/mms_task_encode.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2013-2020 Jolla Ltd. * Copyright (C) 2013-2020 Slava Monich + * Copyright (C) 2020 Open Mobile Platform LLC. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -192,7 +193,7 @@ mms_encode_job_encode( } close(fd); - if (!ok) { + if (!ok && job->path) { unlink(job->path); g_free(job->path); job->path = NULL; @@ -233,7 +234,9 @@ mms_encode_job_run( if (size > 0 && (!size_limit || size <= size_limit)) { job->state = MMS_ENCODE_STATE_DONE; } else { - unlink(job->path); + if (job->path) { + unlink(job->path); + } g_free(job->path); job->path = NULL; job->state = (size > 0) ? MMS_ENCODE_STATE_TOO_BIG : @@ -456,13 +459,8 @@ mms_task_encode_prepare_attachments( for (i=0; i + * Copyright (C) 2013-2020 Jolla Ltd. + * Copyright (C) 2013-2020 Slava Monich + * Copyright (C) 2020 Open Mobile Platform LLC. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -56,6 +57,7 @@ typedef struct test_desc { #define TEST_FLAG_CANCEL (0x1000) #define TEST_FLAG_NO_SIM (0x2000) +#define TEST_FLAG_DONT_CONVERT_TO_UTF8 (0x4000) #define TEST_FLAG_REQUEST_DELIVERY_REPORT MMS_SEND_FLAG_REQUEST_DELIVERY_REPORT #define TEST_FLAG_REQUEST_READ_REPORT MMS_SEND_FLAG_REQUEST_READ_REPORT @@ -65,7 +67,8 @@ typedef struct test_desc { TEST_FLAG_REQUEST_READ_REPORT ) #define TEST_PRIVATE_FLAGS (\ TEST_FLAG_CANCEL |\ - TEST_FLAG_NO_SIM ) + TEST_FLAG_NO_SIM |\ + TEST_FLAG_DONT_CONVERT_TO_UTF8) G_STATIC_ASSERT(!(TEST_PRIVATE_FLAGS & TEST_DISPATCHER_FLAGS)); typedef struct test { @@ -104,7 +107,7 @@ static const MMSAttachmentInfo test_files_reject [] = { }; static const MMSAttachmentInfo test_txt [] = { - { "test.txt", "text/plain", "text" } + { "test.txt", NULL, "text" } }; #define ATTACHMENTS(a) a, G_N_ELEMENTS(a) @@ -254,6 +257,22 @@ static const TestDesc send_tests[] = { MMS_SEND_STATE_TOO_BIG, NULL, NULL + },{ + "DontConvertToUtf8", + ATTACHMENTS(test_txt), + 100, + "No conversion to UTF-8", + "+1234567890", + NULL, + NULL, + NULL, + TEST_FLAG_DONT_CONVERT_TO_UTF8, + NULL, + NULL, + SOUP_STATUS_INTERNAL_SERVER_ERROR, + MMS_SEND_STATE_TOO_BIG, + NULL, + NULL },{ "NoSim", NULL, 0, @@ -445,6 +464,9 @@ test_run_once( { Test test; MMSConfig test_config = *config; + if (desc->flags & TEST_FLAG_DONT_CONVERT_TO_UTF8) { + test_config.convert_to_utf8 = FALSE; + } if (test_init(&test, &test_config, desc)) { GError* error = NULL; char* imsi = desc->imsi ? g_strdup(desc->imsi) : diff --git a/rpm/mms-engine.spec b/rpm/mms-engine.spec index e1b399d..4b917e2 100644 --- a/rpm/mms-engine.spec +++ b/rpm/mms-engine.spec @@ -11,7 +11,7 @@ Source0: %{name}-%{version}.tar.bz2 %define libwspcodec_version 2.2 %define libgofono_version 2.0.0 %define libgofonoext_version 1.0.4 -%define libglibutil_version 1.0.11 +%define libglibutil_version 1.0.47 %define libdbusaccess_version 1.0.10 %define libdbuslog_version 1.0.19