1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include <sstream>
16 #include <iomanip>
17 #include "calendar_log.h"
18 #include "cj_native_util.h"
19 #include <ctime>
20 #include <numeric>
21
22 namespace OHOS::CalendarApi::Native {
23 const int MIN_DAY_OF_WEEK = 1;
24 const int MAX_DAY_OF_WEEK = 7;
25 const int MIN_MONTH_OF_YEAR = -12;
26 const int MAX_MONTH_OF_YEAR = 12;
27 const int MIN_DAY_OF_MONTH = -31;
28 const int MAX_DAY_OF_MONTH = 31;
29 const int MIN_DAY_OF_YEAR = -366;
30 const int MAX_DAY_OF_YEAR = 366;
31 const int MIN_WEEK_OF_YEAR = -53;
32 const int MAX_WEEK_OF_YEAR = 53;
33 const int MIN_WEEK_OF_MONTH = -5;
34 const int MAX_WEEK_OF_MONTH = 5;
DumpCalendarAccount(const CalendarAccount & account)35 void DumpCalendarAccount(const CalendarAccount &account)
36 {
37 LOG_DEBUG("account.name:%{private}s", account.name.c_str());
38 LOG_DEBUG("account.type:%{private}s", account.type.c_str());
39 LOG_DEBUG("account.displayName:%{private}s", account.displayName.value_or("").c_str());
40 }
41
DumpEvent(const Event & event)42 void DumpEvent(const Event &event)
43 {
44 LOG_DEBUG("id :%{private}d", event.id.value_or(-1));
45 LOG_DEBUG("type :%{private}d", event.type);
46 LOG_DEBUG("title :%{private}s", event.title.value_or("[null]").c_str());
47 if (event.location) {
48 auto location = event.location.value();
49 LOG_DEBUG("location.location :%{private}s", location.location.value_or("[null]").c_str());
50 LOG_DEBUG("location.longitude :%{private}lf", location.longitude.value_or(-1));
51 LOG_DEBUG("location.latitude :%{private}lf", location.latitude.value_or(-1));
52 } else {
53 LOG_DEBUG("location [null]");
54 }
55 if (event.service) {
56 auto service = event.service.value();
57 LOG_DEBUG("service.type :%{private}s", service.type.c_str());
58 LOG_DEBUG("service.description :%{private}s", service.description.value_or("[null]").c_str());
59 LOG_DEBUG("service.uri :%{private}s", service.uri.c_str());
60 } else {
61 LOG_DEBUG("service [null]");
62 }
63 if (event.recurrenceRule.has_value()) {
64 LOG_DEBUG("recurrenceRule.recurrenceFrequency: %{private}d", event.recurrenceRule.value().recurrenceFrequency);
65 }
66 LOG_DEBUG("startTime :%{private}s", std::to_string(event.startTime).c_str());
67 LOG_DEBUG("endTime :%{private}s", std::to_string(event.endTime).c_str());
68 LOG_DEBUG("isAllDay :%{private}d", event.isAllDay.value_or(0));
69
70 for (const auto &attendee : event.attendees) {
71 LOG_DEBUG("attendee.name :%{private}s", attendee.name.c_str());
72 LOG_DEBUG("attendee.email :%{private}s", attendee.email.c_str());
73 }
74
75 LOG_DEBUG("timeZone :%{private}s", event.timeZone.value_or("[null]").c_str());
76 LOG_DEBUG("description :%{private}s", event.description.value_or("[null]").c_str());
77 }
78
BuildEventLocation(DataShare::DataShareValuesBucket & valuesBucket,const Event & event)79 void BuildEventLocation(DataShare::DataShareValuesBucket &valuesBucket, const Event &event)
80 {
81 if (!event.location) {
82 return;
83 }
84 auto location = event.location.value();
85 if (location.location) {
86 valuesBucket.Put("eventLocation", location.location.value());
87 } else {
88 valuesBucket.Put("eventLocation", "");
89 }
90 if (location.longitude) {
91 // longitude is string in db
92 valuesBucket.Put("location_longitude", std::to_string(location.longitude.value()));
93 } else {
94 valuesBucket.Put("location_longitude", "");
95 }
96 if (location.latitude) {
97 // latitude is string in db
98 valuesBucket.Put("location_latitude", std::to_string(location.latitude.value()));
99 } else {
100 valuesBucket.Put("location_latitude", "");
101 }
102 }
103
BuildEventService(DataShare::DataShareValuesBucket & valuesBucket,const Event & event)104 void BuildEventService(DataShare::DataShareValuesBucket &valuesBucket, const Event &event)
105 {
106 if (!event.service.has_value()) {
107 LOG_INFO("BuildEventService event.service has no value ");
108 return;
109 }
110 const auto service = event.service.value();
111 if (service.description) {
112 valuesBucket.Put("service_description", service.description.value());
113 } else {
114 valuesBucket.Put("service_description", "");
115 }
116 valuesBucket.Put("service_type", service.type);
117 valuesBucket.Put("service_cp_bz_uri", service.uri);
118 }
119
GetUTCTime(const int64_t & timeValue)120 std::string GetUTCTime(const int64_t &timeValue)
121 {
122 const int monOffset = 1;
123 const int strLen = 2;
124 const int baseYear = 1900;
125 time_t expire = timeValue / 1000;
126 std::tm expireTime = {0};
127 #ifdef WINDOWS_PLATFORM
128 if (gmtime_s(&expireTime, &expire)) {
129 #else
130 if (gmtime_r(&expire, &expireTime) == nullptr) {
131 #endif
132 return {};
133 }
134 std::stringstream out;
135 out << (expireTime.tm_year + baseYear);
136 out << std::setfill('0') << std::setw(strLen) << expireTime.tm_mon + monOffset;
137 out << std::setfill('0') << std::setw(strLen) << expireTime.tm_mday;
138 out << "T";
139 out << std::setfill('0') << std::setw(strLen) << expireTime.tm_hour;
140 out << std::setfill('0') << std::setw(strLen) << expireTime.tm_min;
141 out << std::setfill('0') << std::setw(strLen) << expireTime.tm_sec;
142 out << "Z";
143
144 return out.str();
145 }
146
147 std::string GetUTCTimes(const std::vector<int64_t> &timeValues)
148 {
149 std::stringstream out;
150 if (timeValues.size() == 0) {
151 return out.str();
152 }
153
154 const auto timeLen = timeValues.size() - 1;
155 if (timeLen == 0) {
156 out << GetUTCTime(timeValues[0]);
157 return out.str();
158 }
159
160 for (unsigned int i = 0; i <= timeLen; i++) {
161 out << GetUTCTime(timeValues[i]);
162 if (i != timeLen) {
163 out << ",";
164 }
165 }
166
167 return out.str();
168 }
169
170 std::string GetRule(const Event &event)
171 {
172 const time_t now = event.startTime / 1000;
173 const std::tm *time = std::localtime(&now);
174 std::string rrule;
175 RecurrenceType recurrenceFrequency = event.recurrenceRule.value().recurrenceFrequency;
176 if (recurrenceFrequency == DAILY) {
177 rrule = "FREQ=DAILY" + GetEventRRule(event) + ";WKST=SU";
178 } else if (recurrenceFrequency == WEEKLY) {
179 rrule = "FREQ=WEEKLY" + GetEventRRule(event) + ";WKST=SU;BYDAY=";
180 if (time != nullptr) {
181 rrule += GetWeeklyRule(event, *time);
182 }
183 } else if (recurrenceFrequency == MONTHLY) {
184 rrule = "FREQ=MONTHLY" + GetEventRRule(event) + ";WKST=SU";
185 if (time != nullptr) {
186 rrule += GetMonthlyRule(event, *time);
187 }
188 } else if (recurrenceFrequency == YEARLY) {
189 rrule = "FREQ=YEARLY" + GetEventRRule(event) + ";WKST=SU";
190 if (time != nullptr) {
191 rrule += GetYearlyRule(event, *time);
192 }
193 } else if (recurrenceFrequency == NORULE) {
194 LOG_INFO(" recurrenceFrequency == NORULE");
195 rrule = "";
196 }
197
198 return rrule;
199 }
200
201 std::string GetEventRRule(const Event &event)
202 {
203 auto recurrenceRule = event.recurrenceRule.value();
204 std::string rrule;
205 if (recurrenceRule.expire.has_value() && recurrenceRule.expire.value() > 0) {
206 rrule += ";UNTIL=" + GetUTCTime(event.recurrenceRule.value().expire.value());
207 }
208 if (recurrenceRule.count.has_value() && recurrenceRule.count.value() > 0) {
209 rrule += ";COUNT=" + std::to_string(recurrenceRule.count.value());
210 }
211 if (recurrenceRule.interval.has_value() && recurrenceRule.interval.value() > 0) {
212 rrule += ";INTERVAL=" + std::to_string(recurrenceRule.interval.value());
213 }
214 return rrule;
215 }
216
217 std::string GetWeeklyRule(const Event &event, const std::tm &time)
218 {
219 std::string rrule;
220 bool isHasSetData = false;
221 auto rRuleValue = event.recurrenceRule.value();
222 const std::vector<string> weekList = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"};
223 if (rRuleValue.daysOfWeek.has_value()) {
224 isHasSetData = true;
225 auto daysOfWeekList = rRuleValue.daysOfWeek.value();
226 rrule = GetDaysOfWeekRule(MIN_DAY_OF_WEEK, MAX_DAY_OF_WEEK, daysOfWeekList);
227 }
228 if (isHasSetData == false) {
229 if (time.tm_wday < MAX_DAY_OF_WEEK) {
230 rrule = weekList[time.tm_wday];
231 }
232 }
233 return rrule;
234 }
235
236 std::string GetMonthlyRule(const Event &event, const std::tm &time)
237 {
238 bool isHasSetData = false;
239 std::string rrule;
240 auto rruleValue = event.recurrenceRule.value();
241 if (rruleValue.daysOfWeek.has_value() && rruleValue.weeksOfMonth.has_value()) {
242 isHasSetData = true;
243 rrule += ";BYDAY=";
244 rrule += GetDaysOfWeekMonthRule(rruleValue.daysOfWeek.value(), rruleValue.weeksOfMonth.value());
245 }
246
247 if (rruleValue.daysOfMonth.has_value()) {
248 isHasSetData = true;
249 rrule += ";BYMONTHDAY=";
250 auto daysOfMonthList = rruleValue.daysOfMonth.value();
251 rrule += GetRRuleSerial(MIN_DAY_OF_MONTH, MAX_DAY_OF_MONTH, daysOfMonthList);
252 }
253 if (isHasSetData == false) {
254 rrule += ";BYMONTHDAY=";
255 rrule += std::to_string(time.tm_mday);
256 }
257 return rrule;
258 }
259
260 std::string GetYearlyRule(const Event &event, const std::tm &time)
261 {
262 const int monOffset = 1;
263 bool isHasSetData = false;
264 std::string rrule;
265 auto rruleValue = event.recurrenceRule.value();
266 if (rruleValue.daysOfYear.has_value()) {
267 isHasSetData = true;
268 std::string days = GetRRuleSerial(MIN_DAY_OF_YEAR, MAX_DAY_OF_YEAR, rruleValue.daysOfYear.value());
269 rrule = ";BYYEARDAY=" + days;
270 }
271 if (rruleValue.weeksOfYear.has_value() && rruleValue.daysOfWeek.has_value()) {
272 isHasSetData = true;
273 auto weekOfYearList = rruleValue.weeksOfYear.value();
274 std::string weeks = GetRRuleSerial(MIN_WEEK_OF_YEAR, MAX_WEEK_OF_YEAR, weekOfYearList);
275 auto daysOfWeekList = rruleValue.daysOfWeek.value();
276 std::string weekdays = GetDaysOfWeekRule(MIN_DAY_OF_WEEK, MAX_DAY_OF_WEEK, daysOfWeekList);
277 rrule = ";BYWEEKNO=" + weeks + ";BYDAY=" + weekdays;
278 }
279 if (rruleValue.monthsOfYear.has_value() && rruleValue.daysOfMonth.has_value()) {
280 isHasSetData = true;
281 auto daysOfMonthList = rruleValue.daysOfMonth.value();
282 auto monthsOfYearList = rruleValue.monthsOfYear.value();
283 std::string days = GetRRuleSerial(MIN_DAY_OF_MONTH, MAX_DAY_OF_MONTH, daysOfMonthList);
284 std::string months = GetRRuleSerial(MIN_MONTH_OF_YEAR, MAX_MONTH_OF_YEAR, monthsOfYearList);
285 rrule = ";BYMONTHDAY=" + days + ";BYMONTH=" + months;
286 }
287 if (rruleValue.monthsOfYear.has_value() && rruleValue.weeksOfMonth.has_value() &&
288 rruleValue.daysOfWeek.has_value()) {
289 isHasSetData = true;
290 auto monthsOfYearList = rruleValue.monthsOfYear.value();
291 auto weeksOfMonthList = rruleValue.weeksOfMonth.value();
292 auto daysOfWeekList = rruleValue.daysOfWeek.value();
293 std::string months = GetRRuleSerial(MIN_MONTH_OF_YEAR, MAX_MONTH_OF_YEAR, monthsOfYearList);
294 std::string daysOfWeekMonth = GetDaysOfWeekMonthRule(daysOfWeekList, weeksOfMonthList);
295 rrule = ";BYDAY=" + daysOfWeekMonth + ";BYMONTH=" + months;
296 }
297 if (isHasSetData == false) {
298 rrule += ";BYMONTHDAY=";
299 rrule += std::to_string(time.tm_mday);
300 rrule += ";BYMONTH=";
301 rrule += std::to_string(time.tm_mon + monOffset);
302 }
303 return rrule;
304 }
305
306 std::string GetDaysOfWeekRule(int minValue, int maxValue, const std::vector<int64_t> &daysOfWeekList)
307 {
308 std::string rrule;
309 const std::vector<string> weekDayList = {"MO", "TU", "WE", "TH", "FR", "SA", "SU"};
310 for (const auto &dayOfWeek : daysOfWeekList) {
311 if (dayOfWeek <= maxValue && dayOfWeek >= minValue) {
312 if (&dayOfWeek == &daysOfWeekList.back()) {
313 rrule = rrule + weekDayList[dayOfWeek - 1];
314 break;
315 }
316 rrule = rrule + weekDayList[dayOfWeek - 1] + ",";
317 }
318 }
319 return rrule;
320 }
321
322 std::string GetDaysOfWeekMonthRule(
323 const std::vector<int64_t> &daysOfWeekList, const std::vector<int64_t> &weeksOfMonthList)
324 {
325 std::string rrule;
326 const std::vector<string> weekDayList = {"MO", "TU", "WE", "TH", "FR", "SA", "SU"};
327 auto daysLen = daysOfWeekList.size();
328 for (size_t i = 0; i < daysLen; i++) {
329 if (daysOfWeekList[i] >= MIN_DAY_OF_WEEK && daysOfWeekList[i] <= MAX_DAY_OF_WEEK &&
330 weeksOfMonthList[i] >= MIN_WEEK_OF_MONTH && weeksOfMonthList[i] <= MAX_WEEK_OF_MONTH) {
331 if (i == daysLen - 1) {
332 rrule = rrule + std::to_string(weeksOfMonthList[i]) + weekDayList[daysOfWeekList[i] - 1];
333 break;
334 } else {
335 rrule = rrule + std::to_string(weeksOfMonthList[i]) + weekDayList[daysOfWeekList[i] - 1] + ",";
336 }
337 }
338 }
339 return rrule;
340 }
341
342 std::string GetRRuleSerial(int minValue, int maxValue, const std::vector<int64_t> &serialList)
343 {
344 std::string rrule;
345 for (const auto &serial : serialList) {
346 if (serial >= minValue && serial <= maxValue) {
347 if (&serial == &serialList.back()) {
348 rrule = rrule + std::to_string(serial);
349 break;
350 }
351 rrule = rrule + std::to_string(serial) + ",";
352 }
353 }
354 return rrule;
355 }
356
357 void BuildEventRecurrenceRule(DataShare::DataShareValuesBucket &valuesBucket, const Event &event)
358 {
359 if (!event.recurrenceRule.has_value()) {
360 return;
361 }
362
363 std::string rrule = GetRule(event);
364 valuesBucket.Put("rrule", rrule);
365
366 if (event.recurrenceRule.value().excludedDates.has_value()) {
367 const auto excludedDateStr = GetUTCTimes(event.recurrenceRule.value().excludedDates.value());
368 valuesBucket.Put("exdate", excludedDateStr);
369 }
370 }
371
372 DataShare::DataShareValuesBucket BuildValueEvent(const Event &event, int calendarId, int channelId, bool isUpdate)
373 {
374 DataShare::DataShareValuesBucket valuesBucket;
375 valuesBucket.Put("calendar_id", calendarId);
376 if (!isUpdate) {
377 LOG_DEBUG("title %{private}s", event.title.value_or("").c_str());
378 valuesBucket.Put("title", event.title.value_or(""));
379 } else {
380 if (event.title) {
381 valuesBucket.Put("title", event.title.value());
382 }
383 }
384 valuesBucket.Put("important_event_type", event.type);
385 valuesBucket.Put("dtstart", event.startTime);
386 valuesBucket.Put("dtend", event.endTime);
387
388 BuildEventLocation(valuesBucket, event);
389 BuildEventService(valuesBucket, event);
390 BuildEventRecurrenceRule(valuesBucket, event);
391
392 LOG_DEBUG("description %{private}s", event.description.value_or("").c_str());
393
394 if (event.description.has_value()) {
395 valuesBucket.Put("description", event.description.value());
396 }
397 if (event.timeZone.has_value()) {
398 valuesBucket.Put("eventTimezone", event.timeZone.value());
399 }
400 if (event.isAllDay.has_value() && event.isAllDay.value() != false) {
401 valuesBucket.Put("allDay", event.isAllDay.value());
402 }
403 if (event.identifier.has_value()) {
404 valuesBucket.Put("identifier", event.identifier.value());
405 }
406 if (event.isLunar.has_value() && event.isLunar.value()!= false) {
407 valuesBucket.Put("event_calendar_type", event.isLunar.value());
408 }
409 return valuesBucket;
410 }
411
412 DataShare::DataShareValuesBucket BuildAttendeeValue(const Attendee &attendee, int eventId)
413 {
414 DataShare::DataShareValuesBucket valuesBucket;
415 valuesBucket.Put("event_id", eventId);
416 valuesBucket.Put("attendeeName", attendee.name);
417 LOG_DEBUG("attendeeName %{private}s", attendee.name.c_str());
418 valuesBucket.Put("attendeeEmail", attendee.email);
419 LOG_DEBUG("attendeeEmail %{private}s", attendee.email.c_str());
420 if (attendee.role.has_value()) {
421 valuesBucket.Put("attendeeRelationship", attendee.role.value());
422 }
423 if (attendee.status.has_value()) {
424 valuesBucket.Put("attendeeStatus", attendee.status.value());
425 }
426 if (attendee.type.has_value()) {
427 valuesBucket.Put("attendeeType", attendee.type.value());
428 }
429
430 return valuesBucket;
431 }
432
433 int GetValue(DataShareResultSetPtr &resultSet, string_view fieldName, int& out)
434 {
435 int index = 0;
436 auto ret = resultSet->GetColumnIndex(string(fieldName), index);
437 if (ret != DataShare::E_OK) {
438 return ret;
439 }
440 return resultSet->GetInt(index, out);
441 }
442
443 int GetIndexValue(const DataShareResultSetPtr &resultSet, int index, std::string& out)
444 {
445 return resultSet->GetString(index, out);
446 }
447
448 int GetIndexValue(const DataShareResultSetPtr &resultSet, int index, int& out)
449 {
450 return resultSet->GetInt(index, out);
451 }
452
453 int GetIndexValue(const DataShareResultSetPtr &resultSet, int index, int64_t& out)
454 {
455 return resultSet->GetLong(index, out);
456 }
457
458 int GetValue(DataShareResultSetPtr &resultSet, string_view fieldName, std::string& out)
459 {
460 int index = 0;
461 auto fieldNameStr = string(fieldName);
462 auto ret = resultSet->GetColumnIndex(fieldNameStr, index);
463 if (ret != DataShare::E_OK) {
464 LOG_WARN("GetValue [%{private}s] failed [%{private}d]", fieldNameStr.c_str(), ret);
465 return ret;
466 }
467 return resultSet->GetString(index, out);
468 }
469
470 std::vector<std::shared_ptr<CJNativeCalendar>> ResultSetToCalendars(DataShareResultSetPtr &resultSet)
471 {
472 std::vector<std::shared_ptr<CJNativeCalendar>> result;
473 int rowCount = 0;
474 resultSet->GetRowCount(rowCount);
475 LOG_INFO("GetRowCount is %{public}d", rowCount);
476 if (rowCount == 0) {
477 return result;
478 }
479 auto err = resultSet->GoToFirstRow();
480 if (err != DataShare::E_OK) {
481 LOG_INFO("Failed GoToFirstRow %{public}d", err);
482 return result;
483 }
484 do {
485 int idValue = -1;
486 if (GetValue(resultSet, "_id", idValue) != DataShare::E_OK) {
487 break;
488 }
489 LOG_DEBUG("id: %{private}d", idValue);
490 std::string nameValue;
491 if (GetValue(resultSet, "account_name", nameValue) != DataShare::E_OK) {
492 break;
493 }
494 LOG_DEBUG("account_name: %{private}s", nameValue.c_str());
495 std::string typeValue;
496 if (GetValue(resultSet, "account_type", typeValue) != DataShare::E_OK) {
497 break;
498 }
499 LOG_DEBUG("account_type: %{private}s", typeValue.c_str());
500
501 std::string displayNameValue;
502 GetValue(resultSet, "calendar_displayName", displayNameValue);
503 LOG_DEBUG("calendar_displayName: %{private}s", displayNameValue.c_str());
504
505 int canReminder = -1;
506 GetValue(resultSet, "canReminder", canReminder);
507 LOG_DEBUG("canReminder: %{private}d", canReminder);
508
509 int colorValue = 0;
510 GetValue(resultSet, "calendar_color", colorValue);
511 CalendarAccount curAccount {nameValue, typeValue, displayNameValue};
512 result.emplace_back(std::make_shared<CJNativeCalendar>(curAccount, idValue));
513 } while (resultSet->GoToNextRow() == DataShare::E_OK);
514 return result;
515 }
516
517 std::optional<Location> ResultSetToLocation(DataShareResultSetPtr &resultSet)
518 {
519 Location out;
520 string value;
521 auto ret = GetValue(resultSet, "eventLocation", value);
522 out.location = std::make_optional<string>(value);
523 ret = GetValue(resultSet, "location_longitude", value);
524 double longitudeValue = -1;
525 std::stringstream str2digit;
526 str2digit << value;
527 str2digit >> longitudeValue;
528 if (longitudeValue != -1) {
529 out.longitude = std::make_optional<double>(longitudeValue);
530 }
531 ret = GetValue(resultSet, "location_latitude", value);
532 double latitudeValue = -1;
533 str2digit.clear();
534 str2digit << value;
535 str2digit >> latitudeValue;
536 if (latitudeValue != -1) {
537 out.latitude = std::make_optional<double>(latitudeValue);
538 }
539
540 if (ret != DataShare::E_OK) {
541 return std::nullopt;
542 }
543 return std::make_optional<Location>(out);
544 }
545
546 std::optional<EventService> ResultSetToEventService(DataShareResultSetPtr &resultSet)
547 {
548 EventService out;
549 string value;
550 auto ret = GetValue(resultSet, "service_type", value);
551 if (ret != DataShare::E_OK) {
552 return std::nullopt;
553 }
554 const std::set<std::string> serviceType = {"Meeting", "Watching", "Repayment", "Live", "Shopping",
555 "Trip", "Class", "SportsEvents", "SportsExercise"};
556 if (serviceType.count(value)) {
557 out.type = value;
558 } else {
559 return std::nullopt;
560 }
561 ret = GetValue(resultSet, "service_cp_bz_uri", value);
562 if (ret != DataShare::E_OK) {
563 return std::nullopt;
564 }
565 out.uri = value;
566 ret = GetValue(resultSet, "service_description", value);
567 if (ret == DataShare::E_OK) {
568 out.description = std::make_optional<string>(value);
569 }
570 return std::make_optional<EventService>(out);
571 }
572
573 int StringToInt(const std::string &str)
574 {
575 try {
576 return std::stoi(str);
577 } catch (std::exception &ex) {
578 LOG_ERROR("StringToInt conversion fail, str: %{public}s", str.c_str());
579 return 0;
580 }
581 }
582
583 std::time_t TimeToUTC(const std::string &strTime)
584 {
585 const int baseYear = 1900;
586 const int offset = 2;
587 const int yearOffset = 4;
588 const int monBase = 4;
589 const int dayBase = 6;
590 const int hourBase = 9;
591 const int minBase = 11;
592 const int secBase = 13;
593 const int monCount = 12;
594 const int monRectify = 11;
595 const int micSecond = 1000;
596 const int timeStrLenMin = 8;
597 const int timeStrLen = 15;
598
599 std::tm expireTime = {0};
600 if (strTime.size() < timeStrLenMin) {
601 LOG_DEBUG("strTime length error");
602 return 0;
603 }
604 expireTime.tm_year = StringToInt(strTime.substr(0, yearOffset)) - baseYear;
605 expireTime.tm_mon = (StringToInt(strTime.substr(monBase, offset)) + monRectify) % monCount;
606 expireTime.tm_mday = StringToInt(strTime.substr(dayBase, offset));
607 if (strTime.find("T") != std::string::npos && strTime.length() >= timeStrLen) {
608 expireTime.tm_hour = StringToInt(strTime.substr(hourBase, offset));
609 expireTime.tm_min = StringToInt(strTime.substr(minBase, offset));
610 expireTime.tm_sec = StringToInt(strTime.substr(secBase, offset));
611 } else {
612 expireTime.tm_hour = 0;
613 expireTime.tm_min = 0;
614 expireTime.tm_sec = 0;
615 }
616
617 std::time_t utcTime = mktime(&expireTime) * micSecond; //精确到微秒
618
619 return utcTime;
620 }
621
622 std::vector<std::string> SplitString(const std::string &str, const std::string &flag)
623 {
624 std::vector<std::string> result;
625 std::string::size_type pos1 = 0;
626 std::string::size_type pos2 = str.find(flag);
627 while (pos2 != std::string::npos) {
628 result.push_back(str.substr(pos1, pos2 - pos1));
629 pos1 = pos2 + flag.size();
630 pos2 = str.find(flag, pos1);
631 }
632 if (pos1 != str.length()) {
633 result.push_back(str.substr(pos1));
634 }
635
636 return result;
637 }
638
639 std::optional<vector<int64_t>> ResultSetToExcludedDates(DataShareResultSetPtr &resultSet)
640 {
641 std::string value;
642 auto ret = GetValue(resultSet, "exdate", value);
643 if (ret != DataShare::E_OK) {
644 return std::nullopt;
645 }
646 std::vector<string> strListExDate = SplitString(value, ",");
647
648 std::vector<int64_t> excludedDates;
649 for (const auto &str : strListExDate) {
650 auto exDate = TimeToUTC(str);
651 excludedDates.emplace_back(exDate);
652 }
653
654 return std::make_optional<vector<int64_t>>(excludedDates);
655 }
656
657 void ConvertRecurrenceFrequency(const std::string &frequency, RecurrenceRule &rule)
658 {
659 if (frequency == "YEARLY") {
660 rule.recurrenceFrequency = YEARLY;
661 return;
662 }
663 if (frequency == "MONTHLY") {
664 rule.recurrenceFrequency = MONTHLY;
665 return;
666 }
667 if (frequency == "WEEKLY") {
668 rule.recurrenceFrequency = WEEKLY;
669 return;
670 }
671 if (frequency == "DAILY") {
672 rule.recurrenceFrequency = DAILY;
673 }
674 }
675
676 std::optional<RecurrenceRule> ResultSetToRecurrenceRule(DataShareResultSetPtr &resultSet)
677 {
678 const int strListSize = 2;
679 RecurrenceRule out;
680 out.recurrenceFrequency = NORULE;
681 std::string value;
682 auto ret = GetValue(resultSet, "rrule", value);
683 if (ret != DataShare::E_OK) {
684 return std::nullopt;
685 }
686 std::map<std::string, std::string> ruleMap;
687 std::vector<std::string> strListRule = SplitString(value, ";");
688 for (const auto &str : strListRule) {
689 std::vector<std::string> keyAndValue = SplitString(str, "=");
690 if (keyAndValue.size() == strListSize) {
691 ruleMap.insert(std::pair<std::string, std::string>(keyAndValue[0], keyAndValue[1]));
692 }
693 }
694 SetRRuleValue(ruleMap, out);
695 out.excludedDates = ResultSetToExcludedDates(resultSet);
696
697 return std::make_optional<RecurrenceRule>(out);
698 }
699
700 void SetVecNum(std::optional<std::vector<int64_t>> &ruleVec, const std::string &ruleStr)
701 {
702 std::vector<std::string> weekNumList = SplitString(ruleStr, ",");
703 for (const auto &weekNum : weekNumList) {
704 ruleVec->push_back(StringToInt(weekNum));
705 }
706 }
707
708 void SetRRuleValue(const std::map<std::string, std::string> &ruleMap, RecurrenceRule &out)
709 {
710 std::map<std::string, std::string>::const_iterator iter;
711 for (iter = ruleMap.begin(); iter != ruleMap.end(); iter++) {
712 if (iter->first == "FREQ") {
713 ConvertRecurrenceFrequency(iter->second, out);
714 continue;
715 }
716 if (iter->first == "COUNT") {
717 out.count = std::make_optional<int64_t>(StringToInt(iter->second));
718 continue;
719 }
720 if (iter->first == "INTERVAL") {
721 out.interval = std::make_optional<int64_t>(StringToInt(iter->second));
722 continue;
723 }
724 if (iter->first == "UNTIL") {
725 out.expire = std::make_optional<int64_t>(TimeToUTC(iter->second));
726 }
727 if (iter->first == "BYDAY") {
728 std::vector<std::string> weekDayList = SplitString(iter->second, ",");
729 SetByDayOfRRule(weekDayList, out);
730 }
731 if (iter->first == "BYWEEKNO") {
732 out.weeksOfYear = std::make_optional<std::vector<int64_t>>();
733 SetVecNum(out.weeksOfYear, iter->second);
734 }
735 if (iter->first == "BYMONTHDAY") {
736 out.daysOfMonth = std::make_optional<std::vector<int64_t>>();
737 SetVecNum(out.daysOfMonth, iter->second);
738 }
739 if (iter->first == "BYYEARDAY") {
740 out.daysOfYear = std::make_optional<std::vector<int64_t>>();
741 SetVecNum(out.daysOfYear, iter->second);
742 }
743 if (iter->first == "BYMONTH") {
744 out.monthsOfYear = std::make_optional<std::vector<int64_t>>();
745 SetVecNum(out.monthsOfYear, iter->second);
746 }
747 }
748 }
749
750 void SetByDayOfRRule(const std::vector<std::string> &weekDayList, RecurrenceRule &out)
751 {
752 const int weekStrLen = 2;
753 const std::vector<string> dayOfWeekList = {"MO", "TU", "WE", "TH", "FR", "SA", "SU"};
754 out.daysOfWeek = std::make_optional<vector<int64_t>>();
755 out.weeksOfMonth = std::make_optional<vector<int64_t>>();
756 for (const auto &weekday : weekDayList) {
757 if (weekday.length() > weekStrLen) {
758 std::string weekDayStr = weekday.substr(weekday.length() - weekStrLen, weekStrLen);
759 std::string WeekNumStr = weekday.substr(0, weekday.length() - weekStrLen);
760 auto it = std::find(dayOfWeekList.begin(), dayOfWeekList.end(), weekDayStr);
761 if (it != dayOfWeekList.end()) {
762 int dayNum = it - dayOfWeekList.begin();
763 out.daysOfWeek->push_back(dayNum + 1);
764 out.weeksOfMonth->push_back(StringToInt(WeekNumStr));
765 }
766 } else if (weekday.length() == weekStrLen) {
767 auto it = std::find(dayOfWeekList.begin(), dayOfWeekList.end(), weekday);
768 if (it != dayOfWeekList.end()) {
769 int dayNum = it - dayOfWeekList.begin();
770 out.daysOfWeek->push_back(dayNum + 1);
771 }
772 }
773 }
774 }
775
776 void ResultSetToInstanceTime(Event &event, DataShareResultSetPtr &resultSet, const std::set<std::string>& columns)
777 {
778 if (columns.count("instanceStartTime")) {
779 GetValueOptional(resultSet, "begin", event.instanceStartTime);
780 }
781
782 if (columns.count("instanceEndTime")) {
783 GetValueOptional(resultSet, "end", event.instanceEndTime);
784 }
785 }
786
787 void ResultSetToEvent(Event &event, DataShareResultSetPtr &resultSet, const std::set<std::string>& columns)
788 {
789 GetValueOptional(resultSet, "_id", event.id);
790 if (columns.count("type")) {
791 int type = 0;
792 GetValue(resultSet, "important_event_type", type);
793 event.type = static_cast<EventType>(type);
794 }
795 if (columns.count("title")) {
796 GetValueOptional(resultSet, "title", event.title);
797 }
798 if (columns.count("startTime")) {
799 LOG_DEBUG("TLQ get startTime");
800 GetValue(resultSet, "dtstart", event.startTime);
801 }
802 if (columns.count("endTime")) {
803 LOG_DEBUG("TLQ get endTime");
804 GetValue(resultSet, "dtend", event.endTime);
805 }
806 if (columns.count("isAllDay")) {
807 int isAllDay = 0;
808 GetValue(resultSet, "allDay", isAllDay);
809 event.isAllDay = static_cast<bool>(isAllDay);
810 }
811 if (columns.count("description")) {
812 GetValueOptional(resultSet, "description", event.description);
813 }
814 if (columns.count("timeZone")) {
815 GetValueOptional(resultSet, "eventTimezone", event.timeZone);
816 }
817 if (columns.count("location")) {
818 event.location = ResultSetToLocation(resultSet);
819 }
820 if (columns.count("service")) {
821 event.service = ResultSetToEventService(resultSet);
822 }
823 if (columns.count("recurrenceRule")) {
824 event.recurrenceRule = ResultSetToRecurrenceRule(resultSet);
825 }
826
827 if (columns.count("identifier")) {
828 GetValueOptional(resultSet, "identifier", event.identifier);
829 }
830 if (columns.count("isLunar")) {
831 int isLunar = 0;
832 GetValue(resultSet, "event_calendar_type", isLunar);
833 event.isLunar = static_cast<bool>(isLunar);
834 }
835 ResultSetToInstanceTime(event, resultSet, columns);
836 }
837
838 int ResultSetToEvents(std::vector<Event> &events, DataShareResultSetPtr &resultSet,
839 const std::set<std::string>& columns)
840 {
841 int rowCount = 0;
842 resultSet->GetRowCount(rowCount);
843 LOG_INFO("GetRowCount is %{public}d", rowCount);
844 if (rowCount <= 0) {
845 return -1;
846 }
847 auto err = resultSet->GoToFirstRow();
848 if (err != DataShare::E_OK) {
849 LOG_ERROR("Failed GoToFirstRow %{public}d", err);
850 return -1;
851 }
852 do {
853 Event event;
854 ResultSetToEvent(event, resultSet, columns);
855 events.emplace_back(event);
856 } while (resultSet->GoToNextRow() == DataShare::E_OK);
857 return 0;
858 }
859
860 void ResultSetToAttendeeStatus(Attendee &attendee, DataShareResultSetPtr &resultSet)
861 {
862 int statusValue = 0;
863 GetValue(resultSet, "attendeeStatus", statusValue);
864 if (statusValue == UNKNOWN) {
865 attendee.status = std::make_optional<AttendeeStatus>(UNKNOWN);
866 } else if (statusValue == TENTATIVE) {
867 attendee.status = std::make_optional<AttendeeStatus>(TENTATIVE);
868 } else if (statusValue == ACCEPTED) {
869 attendee.status = std::make_optional<AttendeeStatus>(ACCEPTED);
870 } else if (statusValue == DECLINED) {
871 attendee.status = std::make_optional<AttendeeStatus>(DECLINED);
872 } else {
873 attendee.status = std::make_optional<AttendeeStatus>(UNRESPONSIVE);
874 }
875 }
876
877 void ResultSetToAttendeeType(Attendee &attendee, DataShareResultSetPtr &resultSet)
878 {
879 int typeValue = 0;
880 GetValue(resultSet, "attendeeType", typeValue);
881 if (typeValue == REQUIRED) {
882 attendee.type = std::make_optional<AttendeeType>(REQUIRED);
883 } else if (typeValue == OPTIONAL) {
884 attendee.type = std::make_optional<AttendeeType>(OPTIONAL);
885 } else {
886 attendee.type = std::make_optional<AttendeeType>(RESOURCE);
887 }
888 }
889
890 int ResultSetToAttendees(std::vector<Attendee> &attendees, DataShareResultSetPtr &resultSet)
891 {
892 int rowCount = 0;
893 resultSet->GetRowCount(rowCount);
894 LOG_INFO("GetRowCount is %{public}d", rowCount);
895 if (rowCount <= 0) {
896 return -1;
897 }
898 auto err = resultSet->GoToFirstRow();
899 if (err != DataShare::E_OK) {
900 LOG_ERROR("Failed GoToFirstRow %{public}d", err);
901 return -1;
902 }
903 int roleValue = 0;
904 do {
905 Attendee attendee;
906 GetValue(resultSet, "attendeeName", attendee.name);
907 GetValue(resultSet, "attendeeEmail", attendee.email);
908 GetValue(resultSet, "attendeeRelationship", roleValue);
909 if (roleValue == PARTICIPANT) {
910 attendee.role = std::make_optional<RoleType>(PARTICIPANT);
911 } else if (roleValue == ORGANIZER) {
912 attendee.role = std::make_optional<RoleType>(ORGANIZER);
913 }
914
915 ResultSetToAttendeeStatus(attendee, resultSet);
916 ResultSetToAttendeeType(attendee, resultSet);
917 attendees.emplace_back(attendee);
918 } while (resultSet->GoToNextRow() == DataShare::E_OK);
919 return 0;
920 }
921
922 std::string EventIdsToString(const std::vector<int> &ids) {
923 if (ids.empty()) {
924 return "";
925 }
926 return std::accumulate(std::next(ids.begin()), ids.end(), std::to_string(ids[0]),
927 [](const std::string& a, int b) {
928 std::stringstream ss;
929 ss << a << ", " << b;
930 return ss.str();
931 }
932 );
933 }
934
935 int ResultSetToReminders(std::vector<int> &reminders, DataShareResultSetPtr &resultSet)
936 {
937 int rowCount = 0;
938 resultSet->GetRowCount(rowCount);
939 LOG_INFO("GetRowCount is %{public}d", rowCount);
940 if (rowCount <= 0) {
941 return -1;
942 }
943 auto err = resultSet->GoToFirstRow();
944 if (err != DataShare::E_OK) {
945 LOG_ERROR("Failed GoToFirstRow %{public}d", err);
946 return -1;
947 }
948 do {
949 int minutes = 0;
950 GetValue(resultSet, "minutes", minutes);
951 reminders.emplace_back(minutes);
952 } while (resultSet->GoToNextRow() == DataShare::E_OK);
953 return 0;
954 }
955
956 void ResultSetToConfig(CalendarConfig &config, DataShareResultSetPtr &resultSet)
957 {
958 int rowCount = 0;
959 resultSet->GetRowCount(rowCount);
960 LOG_INFO("GetRowCount is %{public}d", rowCount);
961 auto err = resultSet->GoToFirstRow();
962 if (err != DataShare::E_OK) {
963 LOG_ERROR("Failed GoToFirstRow %{public}d", err);
964 }
965 do {
966 int enableReminder = 0;
967 std::int64_t color = 0;
968 GetValue(resultSet, "canReminder", enableReminder);
969 GetValue(resultSet, "calendar_color", color);
970 config.enableReminder = static_cast<bool>(enableReminder);
971 LOG_INFO("enableReminder is %{public}d", enableReminder);
972 config.color = color;
973 } while (resultSet->GoToNextRow() == DataShare::E_OK);
974 }
975
976 bool IsValidHexString(const std::string& colorStr)
977 {
978 if (colorStr.empty()) {
979 return false;
980 }
981 for (char ch : colorStr) {
982 if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
983 continue;
984 }
985 return false;
986 }
987 return true;
988 }
989
990 bool ColorParse(const std::string& colorStr, variant<string, int64_t>& colorValue)
991 {
992 if (colorStr.empty()) {
993 LOG_ERROR("color string is empty");
994 return false;
995 }
996
997 if (colorStr[0] != '#') { // start with '#'
998 LOG_ERROR("color string not start with #");
999 return false;
1000 }
1001
1002 const int rgbLen = 7;
1003 const int argbLen = 9;
1004 if (colorStr.size() != rgbLen && colorStr.size() != argbLen) {
1005 LOG_ERROR("color string length is not 7 or 9");
1006 return false;
1007 }
1008
1009 std::string colorStrSub = colorStr.substr(1);
1010 if (!IsValidHexString(colorStrSub)) {
1011 LOG_DEBUG("color string is not valid hex string");
1012 return false;
1013 }
1014
1015 LOG_DEBUG("color string size is 7 or 9");
1016 try {
1017 colorValue.emplace<1>(std::stoll(colorStrSub, NULL, 16)); // 16 is convert hex string to number
1018 } catch (std::exception &ex) {
1019 LOG_ERROR("stoll fail %{public}s", ex.what());
1020 return false;
1021 }
1022 if (std::get_if<1>(&colorValue)) {
1023 LOG_DEBUG("colorStrSub -> colorValue colorValue:%{public}s", std::to_string(std::get<1>(colorValue)).c_str());
1024 return true;
1025 }
1026 LOG_DEBUG("color is null");
1027 return false;
1028 }
1029
1030 void SetLocationFieldInfo(std::vector<string>& queryField)
1031 {
1032 queryField.emplace_back("eventLocation");
1033 queryField.emplace_back("location_longitude");
1034 queryField.emplace_back("location_latitude");
1035 }
1036
1037 void SetServiceFieldInfo(std::vector<string>& queryField)
1038 {
1039 queryField.emplace_back("service_type");
1040 queryField.emplace_back("service_cp_bz_uri");
1041 queryField.emplace_back("service_description");
1042 }
1043
1044 void FillFieldInfo(const std::string field, std::vector<string>& queryField, std::set<string>& resultSetField,
1045 const std::map<string, string> eventField)
1046 {
1047 if (field == "location") {
1048 SetLocationFieldInfo(queryField);
1049 resultSetField.insert(field);
1050 return;
1051 }
1052 if (field == "service") {
1053 SetServiceFieldInfo(queryField);
1054 resultSetField.insert(field);
1055 return;
1056 }
1057 if (field == "attendee") {
1058 resultSetField.insert(field);
1059 return;
1060 }
1061 if (field == "reminderTime") {
1062 resultSetField.insert(field);
1063 return;
1064 }
1065 if (field == "identifier") {
1066 queryField.emplace_back("identifier");
1067 resultSetField.insert(field);
1068 return;
1069 }
1070 if (field == "recurrenceRule") {
1071 queryField.emplace_back("rrule");
1072 queryField.emplace_back("exdate");
1073 resultSetField.insert(field);
1074 return;
1075 }
1076 if (field == "isLunar") {
1077 queryField.emplace_back("event_calendar_type");
1078 resultSetField.insert(field);
1079 return;
1080 }
1081 if (field == "instanceStartTime") {
1082 queryField.emplace_back("begin");
1083 resultSetField.insert(field);
1084 return;
1085 }
1086 if (field == "instanceEndTime") {
1087 queryField.emplace_back("end");
1088 resultSetField.insert(field);
1089 return;
1090 }
1091 queryField.emplace_back(eventField.at(field));
1092 resultSetField.insert(field);
1093 }
1094
1095 void SetFieldInfo(const std::vector<string>& eventKey, std::vector<string>& queryField,
1096 std::set<string>& resultSetField, const std::map<string, string> eventField)
1097 {
1098 for (const auto& field : eventKey) {
1099 if (field == "id") {
1100 continue;
1101 }
1102 FillFieldInfo(field, queryField, resultSetField, eventField);
1103 }
1104 }
1105
1106 void SetField(const std::vector<string>& eventKey, std::vector<string>& queryField, std::set<string>& resultSetField)
1107 {
1108 const std::map<string, string> eventField = { { "id", "_id" },
1109 { "type", "important_event_type" },
1110 { "title", "title" },
1111 { "startTime", "dtstart" },
1112 { "endTime", "dtend" },
1113 { "isAllDay", "allDay" },
1114 { "timeZone", "eventTimezone" },
1115 { "description", "description" }};
1116 SetFieldInfo(eventKey, queryField, resultSetField, eventField);
1117 }
1118 }