diff options
Diffstat (limited to 'src/engine-eds.cpp')
-rw-r--r-- | src/engine-eds.cpp | 189 |
1 files changed, 144 insertions, 45 deletions
diff --git a/src/engine-eds.cpp b/src/engine-eds.cpp index a47ab4a..b91fd71 100644 --- a/src/engine-eds.cpp +++ b/src/engine-eds.cpp @@ -25,6 +25,7 @@ #include <libedataserver/libedataserver.h> #include <algorithm> // std::sort() +#include <array> #include <ctime> // time() #include <map> #include <set> @@ -128,12 +129,18 @@ public: auto extension = e_source_get_extension(source, E_SOURCE_EXTENSION_CALENDAR); const auto color = e_source_selectable_get_color(E_SOURCE_SELECTABLE(extension)); g_debug("calling e_cal_client_generate_instances for %p", (void*)client); + auto subtask = new AppointmentSubtask(main_task, + client, + color, + default_timezone, + begin_timet, + end_timet); e_cal_client_generate_instances(client, begin_timet, end_timet, m_cancellable, my_get_appointments_foreach, - new AppointmentSubtask (main_task, client, color), + subtask, [](gpointer g){delete static_cast<AppointmentSubtask*>(g);}); } } @@ -411,14 +418,70 @@ private: std::shared_ptr<Task> task; ECalClient* client; std::string color; - AppointmentSubtask(const std::shared_ptr<Task>& task_in, ECalClient* client_in, const char* color_in): - task(task_in), client(client_in) + icaltimezone* default_timezone; + time_t begin; + time_t end; + + AppointmentSubtask(const std::shared_ptr<Task>& task_in, + ECalClient* client_in, + const char* color_in, + icaltimezone* default_tz, + time_t begin_, + time_t end_): + task(task_in), + client(client_in), + default_timezone(default_tz), + begin(begin_), + end(end_) { if (color_in) color = color_in; } }; + static std::string get_alarm_text(ECalComponentAlarm * alarm) + { + std::string ret; + + ECalComponentAlarmAction action; + e_cal_component_alarm_get_action(alarm, &action); + if (action == E_CAL_COMPONENT_ALARM_DISPLAY) + { + ECalComponentText text {}; + e_cal_component_alarm_get_description(alarm, &text); + if (text.value) + ret = text.value; + } + + return ret; + } + + static std::string get_alarm_sound_url(ECalComponentAlarm * alarm) + { + std::string ret; + + ECalComponentAlarmAction action; + e_cal_component_alarm_get_action(alarm, &action); + if (action == E_CAL_COMPONENT_ALARM_AUDIO) + { + icalattach* attach = nullptr; + e_cal_component_alarm_get_attach(alarm, &attach); + if (attach != nullptr) + { + if (icalattach_get_is_url (attach)) + { + const char* url = icalattach_get_url(attach); + if (url != nullptr) + ret = url; + } + + icalattach_unref(attach); + } + } + + return ret; + } + static gboolean my_get_appointments_foreach(ECalComponent* component, time_t begin, @@ -436,11 +499,16 @@ private: auto status = ICAL_STATUS_NONE; e_cal_component_get_status(component, &status); - const auto begin_dt = DateTime(begin); - const auto end_dt = DateTime(end); + // get the timezone we want to use for generated Appointments/Alarms + const char * location = icaltimezone_get_location(subtask->default_timezone); + auto gtz = g_time_zone_new(location); + g_debug("timezone abbreviation is %s", g_time_zone_get_abbreviation (gtz, 0)); + + const DateTime begin_dt { gtz, begin }; + const DateTime end_dt { gtz, end }; g_debug ("got appointment from %s to %s, uid %s status %d", - begin_dt.format("%F %T").c_str(), - end_dt.format("%F %T").c_str(), + begin_dt.format("%F %T %z").c_str(), + end_dt.format("%F %T %z").c_str(), uid, (int)status); @@ -463,10 +531,10 @@ private: (status != ICAL_STATUS_COMPLETED) && (status != ICAL_STATUS_CANCELLED)) { + constexpr std::array<ECalComponentAlarmAction,1> omit = { (ECalComponentAlarmAction)-1 }; // list of action types to omit, terminated with -1 Appointment appointment; - ECalComponentText text; - text.value = nullptr; + ECalComponentText text {}; e_cal_component_get_summary(component, &text); if (text.value) appointment.summary = text.value; @@ -495,49 +563,80 @@ private: appointment.uid = uid; appointment.type = type; - // Look through all of this component's alarms - // for DISPLAY or AUDIO url attachments. - // If we find any, use them for appointment.url and audio_sound - auto alarm_uids = e_cal_component_get_alarm_uids(component); - for(auto walk=alarm_uids; appointment.url.empty() && walk!=nullptr; walk=walk->next) + icalcomponent * icc = e_cal_component_get_icalcomponent(component); + g_debug("%s", icalcomponent_as_ical_string(icc)); // libical owns this string; no leak + + auto e_alarms = e_cal_util_generate_alarms_for_comp(component, + subtask->begin, + subtask->end, + const_cast<ECalComponentAlarmAction*>(omit.data()), + e_cal_client_resolve_tzid_cb, + subtask->client, + subtask->default_timezone); + + std::map<DateTime,Alarm> alarms; + + if (e_alarms != nullptr) { - auto alarm = e_cal_component_get_alarm(component, static_cast<const char*>(walk->data)); + for (auto l=e_alarms->alarms; l!=nullptr; l=l->next) + { + auto ai = static_cast<ECalComponentAlarmInstance*>(l->data); + auto a = e_cal_component_get_alarm(component, ai->auid); + + if (a != nullptr) + { + const DateTime alarm_begin{gtz, ai->trigger}; + auto& alarm = alarms[alarm_begin]; + + if (alarm.text.empty()) + alarm.text = get_alarm_text(a); + if (alarm.audio_url.empty()) + alarm.audio_url = get_alarm_sound_url(a); + if (!alarm.time.is_set()) + alarm.time = alarm_begin; - ECalComponentAlarmAction action; - e_cal_component_alarm_get_action(alarm, &action); - if ((action == E_CAL_COMPONENT_ALARM_DISPLAY) || (action == E_CAL_COMPONENT_ALARM_AUDIO)) + e_cal_component_alarm_free(a); + } + } + + e_cal_component_alarms_free(e_alarms); + } + // Hm, no alarm triggers? + // That's a bug in alarms created by some versions of ubuntu-ui-toolkit. + // If that's what's happening here, let's handle those alarms anyway + // by effectively injecting a TRIGGER;VALUE=DURATION;RELATED=START:PT0S + else if (appointment.is_ubuntu_alarm()) + { + Alarm tmp; + tmp.time = appointment.begin; + + auto auids = e_cal_component_get_alarm_uids(component); + for(auto l=auids; l!=nullptr; l=l->next) { - icalattach* attach = nullptr; - e_cal_component_alarm_get_attach(alarm, &attach); - if (attach != nullptr) + const auto auid = static_cast<const char*>(l->data); + auto a = e_cal_component_get_alarm(component, auid); + if (a != nullptr) { - if (icalattach_get_is_url (attach)) - { - const char* url = icalattach_get_url(attach); - if (url != nullptr) - { - if ((action == E_CAL_COMPONENT_ALARM_DISPLAY) && appointment.url.empty()) - { - appointment.url = url; - } - else if ((action == E_CAL_COMPONENT_ALARM_AUDIO) && appointment.audio_url.empty()) - { - appointment.audio_url = url; - } - } - } - - icalattach_unref(attach); + if (tmp.text.empty()) + tmp.text = get_alarm_text(a); + if (tmp.audio_url.empty()) + tmp.audio_url = get_alarm_sound_url(a); + e_cal_component_alarm_free(a); } } + cal_obj_uid_list_free(auids); - e_cal_component_alarm_free(alarm); + alarms[tmp.time] = tmp; } - cal_obj_uid_list_free(alarm_uids); - g_debug("adding appointment '%s' '%s'", appointment.summary.c_str(), appointment.url.c_str()); + appointment.alarms.reserve(alarms.size()); + for (const auto& it : alarms) + appointment.alarms.push_back(it.second); + subtask->task->appointments.push_back(appointment); } + + g_time_zone_unref(gtz); } return G_SOURCE_CONTINUE; @@ -611,10 +710,10 @@ private: std::set<ESource*> m_sources; std::map<ESource*,ECalClient*> m_clients; std::map<ESource*,ECalClientView*> m_views; - GCancellable* m_cancellable = nullptr; - ESourceRegistry* m_source_registry = nullptr; - guint m_rebuild_tag = 0; - time_t m_rebuild_deadline = 0; + GCancellable* m_cancellable {}; + ESourceRegistry* m_source_registry {}; + guint m_rebuild_tag {}; + time_t m_rebuild_deadline {}; }; /*** |