@@ -2484,6 +2484,136 @@ static bool oxcical_import_events(const char *str_zone, uint16_t calendartype,
24842484 return true ;
24852485}
24862486
2487+ #define E_2201 " E-2201: get_propids failed for an unspecified reason"
2488+
2489+ static const char *oxcical_import_todo (const ical &pical,
2490+ const ical_component &comp, EXT_BUFFER_ALLOC alloc,
2491+ GET_PROPIDS get_propids, MESSAGE_CONTENT *pmsg)
2492+ {
2493+ static constexpr uint8_t le_true = 1 ;
2494+ namemap phash;
2495+ uint16_t last_propid = 0x8000 ;
2496+ if (!oxcical_parse_categories (comp, phash, &last_propid, pmsg))
2497+ return " E-2191: oxcical_parse_categories returned an unspecified error" ;
2498+ if (!oxcical_parse_class (comp, pmsg))
2499+ return " E-2192: oxcical_parse_class returned an unspecified error" ;
2500+ if (!oxcical_parse_body (comp, " " , pmsg))
2501+ return " E-2705: oxcical_parse_body returned an unspecified error" ;
2502+ if (!oxcical_parse_html (comp, pmsg))
2503+ return " E-2193: oxcical_parse_html returned an unspecified error" ;
2504+ if (!oxcical_parse_dtstamp (comp, " " , phash, &last_propid, pmsg))
2505+ return " E-2194: oxcical_parse_dtstamp returned an unspecified error" ;
2506+ if (!oxcical_parse_summary (comp, pmsg, alloc, nullptr , nullptr ))
2507+ return " E-2706: oxcical_parse_summary returned an unspecified error" ;
2508+
2509+ const PROPERTY_NAME namequeries[] = {
2510+ {MNID_ID, PSETID_Task, PidLidTaskStatus},
2511+ {MNID_ID, PSETID_Task, PidLidPercentComplete},
2512+ {MNID_ID, PSETID_Task, PidLidTaskStartDate},
2513+ {MNID_ID, PSETID_Task, PidLidTaskDueDate},
2514+ {MNID_ID, PSETID_Task, PidLidTaskDateCompleted},
2515+ {MNID_ID, PSETID_Task, PidLidTaskComplete},
2516+ };
2517+ enum { l_status = 0 , l_pct, l_start, l_due, l_completed, l_completeflag };
2518+ static_assert (l_completeflag + 1 == std::size (namequeries));
2519+ const PROPNAME_ARRAY propnames = {std::size (namequeries), deconst (namequeries)};
2520+ PROPID_ARRAY propids;
2521+ if (!get_propids (&propnames, &propids) || propids.size () != propnames.size ())
2522+ return E_2201;
2523+
2524+ auto line = comp.get_line (" STATUS" );
2525+ if (line != nullptr ) {
2526+ auto val = line->get_first_subvalue ();
2527+ if (val != nullptr ) {
2528+ uint32_t v;
2529+ if (strcasecmp (val, " NEEDS-ACTION" ) == 0 )
2530+ v = tsvNotStarted;
2531+ else if (strcasecmp (val, " COMPLETED" ) == 0 )
2532+ v = tsvComplete;
2533+ else if (strcasecmp (val, " IN-PROGRESS" ) == 0 )
2534+ v = tsvInProgress;
2535+ else if (strcasecmp (val, " CANCELLED" ) == 0 )
2536+ v = tsvDeferred;
2537+ else
2538+ v = tsvNotStarted;
2539+ pmsg->proplist .set (PROP_TAG (PT_LONG, propids[l_status]), &v);
2540+ if (v == tsvComplete)
2541+ pmsg->proplist .set (PROP_TAG (PT_BOOLEAN, propids[l_completeflag]), &le_true);
2542+ }
2543+ }
2544+
2545+ line = comp.get_line (" PERCENT-COMPLETE" );
2546+ if (line != nullptr ) {
2547+ auto val = line->get_first_subvalue ();
2548+ if (val != nullptr ) {
2549+ double d = strtod (val, nullptr ) / 100.0 ;
2550+ pmsg->proplist .set (PROP_TAG (PT_DOUBLE, propids[l_pct]), &d);
2551+ }
2552+ }
2553+
2554+ line = comp.get_line (" DTSTART" );
2555+ if (line != nullptr ) {
2556+ auto tzid = line->get_first_paramval (" TZID" );
2557+ const ical_component *tzc = tzid != nullptr ? oxcical_find_vtimezone (pical, tzid) : nullptr ;
2558+ ical_time itime{};
2559+ time_t utctime;
2560+ if (oxcical_parse_dtvalue (tzc, *line, &itime, &utctime)) {
2561+ auto ntt = rop_util_unix_to_nttime (utctime);
2562+ pmsg->proplist .set (PROP_TAG (PT_SYSTIME, propids[l_start]), &ntt);
2563+ }
2564+ }
2565+
2566+ line = comp.get_line (" DUE" );
2567+ if (line != nullptr ) {
2568+ auto tzid = line->get_first_paramval (" TZID" );
2569+ const ical_component *tzc = tzid != nullptr ? oxcical_find_vtimezone (pical, tzid) : nullptr ;
2570+ ical_time itime{};
2571+ time_t utctime;
2572+ if (oxcical_parse_dtvalue (tzc, *line, &itime, &utctime)) {
2573+ auto ntt = rop_util_unix_to_nttime (utctime);
2574+ pmsg->proplist .set (PROP_TAG (PT_SYSTIME, propids[l_due]), &ntt);
2575+ }
2576+ }
2577+
2578+ line = comp.get_line (" COMPLETED" );
2579+ if (line != nullptr ) {
2580+ auto tzid = line->get_first_paramval (" TZID" );
2581+ const ical_component *tzc = tzid != nullptr ? oxcical_find_vtimezone (pical, tzid) : nullptr ;
2582+ ical_time itime{};
2583+ time_t utctime;
2584+ if (oxcical_parse_dtvalue (tzc, *line, &itime, &utctime)) {
2585+ auto ntt = rop_util_unix_to_nttime (utctime);
2586+ pmsg->proplist .set (PROP_TAG (PT_SYSTIME, propids[l_completed]), &ntt);
2587+ pmsg->proplist .set (PROP_TAG (PT_BOOLEAN, propids[l_completeflag]), &le_true);
2588+ }
2589+ }
2590+
2591+ ical_time itime{};
2592+ oxcical_parse_uid (comp, itime, alloc, phash, &last_propid, pmsg);
2593+ return nullptr ;
2594+ }
2595+
2596+ static const char *oxcical_import_journal (const ical &pical,
2597+ const ical_component &comp, EXT_BUFFER_ALLOC alloc,
2598+ MESSAGE_CONTENT *pmsg)
2599+ {
2600+ namemap phash;
2601+ uint16_t last_propid = 0x8000 ;
2602+ if (!oxcical_parse_categories (comp, phash, &last_propid, pmsg))
2603+ return " E-2191: oxcical_parse_categories returned an unspecified error" ;
2604+ if (!oxcical_parse_class (comp, pmsg))
2605+ return " E-2192: oxcical_parse_class returned an unspecified error" ;
2606+ if (!oxcical_parse_body (comp, " " , pmsg))
2607+ return " E-2705: oxcical_parse_body returned an unspecified error" ;
2608+ if (!oxcical_parse_html (comp, pmsg))
2609+ return " E-2193: oxcical_parse_html returned an unspecified error" ;
2610+ if (!oxcical_parse_dtstamp (comp, " " , phash, &last_propid, pmsg))
2611+ return " E-2194: oxcical_parse_dtstamp returned an unspecified error" ;
2612+ if (!oxcical_parse_summary (comp, pmsg, alloc, nullptr , nullptr ))
2613+ return " E-2706: oxcical_parse_summary returned an unspecified error" ;
2614+ return nullptr ;
2615+ }
2616+
24872617/* *
24882618 * Build a by-UID lookup map for @pical.
24892619 *
@@ -2495,7 +2625,9 @@ static bool oxcical_classify_calendar(const ical &pical, uidxevent_list_t &ul) t
24952625{
24962626 for (const auto &comp : pical.component_list ) {
24972627 auto pcomponent = ∁
2498- if (strcasecmp (pcomponent->m_name .c_str (), " VEVENT" ) != 0 )
2628+ if (strcasecmp (pcomponent->m_name .c_str (), " VEVENT" ) != 0 &&
2629+ strcasecmp (pcomponent->m_name .c_str (), " VTODO" ) != 0 &&
2630+ strcasecmp (pcomponent->m_name .c_str (), " VJOURNAL" ) != 0 )
24992631 continue ;
25002632 auto piline = pcomponent->get_line (" UID" );
25012633 auto puid = piline != nullptr ? piline->get_first_subvalue () : nullptr ;
@@ -2580,6 +2712,40 @@ ec_error_t oxcical_import_multi(const char *str_zone, const ical &pical,
25802712 mlog (LV_ERR, " E-2412: iCal import data contained no VEVENTs with UIDs" );
25812713 return ecNotFound;
25822714 }
2715+ auto first_comp = uid_list.begin ()->second .front ();
2716+ if (strcasecmp (first_comp->m_name .c_str (), " VTODO" ) == 0 ) {
2717+ message_ptr msg (message_content_init ());
2718+ if (msg == nullptr )
2719+ return ecMAPIOOM;
2720+ msgvec.push_back (std::move (msg));
2721+ auto pmsg = msgvec.back ().get ();
2722+ if (pmsg->proplist .set (PR_MESSAGE_CLASS, " IPM.Task" ) != ecSuccess)
2723+ return ecError;
2724+ auto err = oxcical_import_todo (pical, *first_comp, alloc,
2725+ get_propids, pmsg);
2726+ if (err != nullptr ) {
2727+ mlog (LV_ERR, " %s" , err);
2728+ return ecError;
2729+ }
2730+ finalvec.insert (finalvec.end (), std::make_move_iterator (msgvec.begin ()), std::make_move_iterator (msgvec.end ()));
2731+ return ecSuccess;
2732+ } else if (strcasecmp (first_comp->m_name .c_str (), " VJOURNAL" ) == 0 ) {
2733+ message_ptr msg (message_content_init ());
2734+ if (msg == nullptr )
2735+ return ecMAPIOOM;
2736+ msgvec.push_back (std::move (msg));
2737+ auto pmsg = msgvec.back ().get ();
2738+ if (pmsg->proplist .set (PR_MESSAGE_CLASS, " IPM.Activity" ) != ecSuccess)
2739+ return ecError;
2740+ auto err = oxcical_import_journal (pical, *first_comp, alloc,
2741+ pmsg);
2742+ if (err != nullptr ) {
2743+ mlog (LV_ERR, " %s" , err);
2744+ return ecError;
2745+ }
2746+ finalvec.insert (finalvec.end (), std::make_move_iterator (msgvec.begin ()), std::make_move_iterator (msgvec.end ()));
2747+ return ecSuccess;
2748+ }
25832749 piline = pical.get_line (" METHOD" );
25842750 if (piline == nullptr ) {
25852751 if (!oxcical_import_events (str_zone, calendartype,
@@ -3192,8 +3358,6 @@ static void oxcical_export_organizer(const MESSAGE_CONTENT &msg,
31923358 line->append_param (" CN" , str);
31933359}
31943360
3195- #define E_2201 " E-2201: get_propids failed for an unspecified reason"
3196-
31973361static const char *oxcical_export_uid (const MESSAGE_CONTENT &msg,
31983362 ical_component &com, EXT_BUFFER_ALLOC alloc, GET_PROPIDS get_propids)
31993363{
@@ -3508,6 +3672,7 @@ static std::string oxcical_export_internal(const char *method, const char *tzid,
35083672 auto icaltype = " VEVENT" ;
35093673 const char *partstat = nullptr ;
35103674 bool b_proposal = false , b_exceptional = true , b_recurrence = false ;
3675+ bool is_task = false ;
35113676 if (method == nullptr ) {
35123677 b_exceptional = false ;
35133678 if (class_match_prefix (str, " IPM.Appointment" ) == 0 ) {
@@ -3537,6 +3702,7 @@ static std::string oxcical_export_internal(const char *method, const char *tzid,
35373702 method = " " ;
35383703 icaltype = nullptr ;
35393704 pical.m_name = " VTODO" ;
3705+ is_task = true ;
35403706 } else if (class_match_prefix (str, " IPM.Activity" ) == 0 ) {
35413707 method = " " ;
35423708 icaltype = nullptr ;
@@ -3762,10 +3928,12 @@ static std::string oxcical_export_internal(const char *method, const char *tzid,
37623928 ptz_component != nullptr ? tzid : nullptr );
37633929 }
37643930
3765- err = oxcical_export_task (*pmsg, *pcomponent, ptz_component,
3766- tzid, get_propids);
3767- if (err != nullptr )
3768- return err;
3931+ if (is_task) {
3932+ err = oxcical_export_task (*pmsg, *pcomponent, ptz_component,
3933+ tzid, get_propids);
3934+ if (err != nullptr )
3935+ return err;
3936+ }
37693937
37703938 auto sa = pmsg->proplist .get <const STRING_ARRAY>(PROP_TAG (PT_MV_UNICODE, propids[l_keywords]));
37713939 if (sa != nullptr ) {
0 commit comments