1 /*
2 * Copyright (c) 2023 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 "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 valuesBucket.Put("channel_id", channelId);
388
389 BuildEventLocation(valuesBucket, event);
390 BuildEventService(valuesBucket, event);
391 BuildEventRecurrenceRule(valuesBucket, event);
392
393 LOG_DEBUG("description %{private}s", event.description.value_or("").c_str());
394
395 if (event.description.has_value()) {
396 valuesBucket.Put("description", event.description.value());
397 }
398 if (event.timeZone.has_value()) {
399 valuesBucket.Put("eventTimezone", event.timeZone.value());
400 }
401 if (event.isAllDay.has_value()) {
402 valuesBucket.Put("allDay", event.isAllDay.value());
403 }
404 if (event.identifier.has_value()) {
405 valuesBucket.Put("identifier", event.identifier.value());
406 }
407 if (event.isLunar.has_value()) {
408 valuesBucket.Put("event_calendar_type", event.isLunar.value());
409 }
410 return valuesBucket;
411 }
412
413 DataShare::DataShareValuesBucket BuildAttendeeValue(const Attendee &attendee, int eventId)
414 {
415 DataShare::DataShareValuesBucket valuesBucket;
416 valuesBucket.Put("event_id", eventId);
417 valuesBucket.Put("attendeeName", attendee.name);
418 LOG_DEBUG("attendeeName %{private}s", attendee.name.c_str());
419 valuesBucket.Put("attendeeEmail", attendee.email);
420 LOG_DEBUG("attendeeEmail %{private}s", attendee.email.c_str());
421 if (attendee.role.has_value()) {
422 valuesBucket.Put("attendeeRelationship", attendee.role.value());
423 }
424 if (attendee.status.has_value()) {
425 valuesBucket.Put("attendeeStatus", attendee.status.value());
426 }
427 if (attendee.type.has_value()) {
428 valuesBucket.Put("attendeeType", attendee.type.value());
429 }
430
431 return valuesBucket;
432 }
433
434 int GetValue(DataShareResultSetPtr &resultSet, string_view fieldName, int& out)
435 {
436 int index = 0;
437 auto ret = resultSet->GetColumnIndex(string(fieldName), index);
438 if (ret != DataShare::E_OK) {
439 return ret;
440 }
441 return resultSet->GetInt(index, out);
442 }
443
444 int GetIndexValue(const DataShareResultSetPtr &resultSet, int index, std::string& out)
445 {
446 return resultSet->GetString(index, out);
447 }
448
449 int GetIndexValue(const DataShareResultSetPtr &resultSet, int index, int& out)
450 {
451 return resultSet->GetInt(index, out);
452 }
453
454 int GetIndexValue(const DataShareResultSetPtr &resultSet, int index, int64_t& out)
455 {
456 return resultSet->GetLong(index, out);
457 }
458
459 int GetValue(DataShareResultSetPtr &resultSet, string_view fieldName, std::string& out)
460 {
461 int index = 0;
462 auto fieldNameStr = string(fieldName);
463 auto ret = resultSet->GetColumnIndex(fieldNameStr, index);
464 if (ret != DataShare::E_OK) {
465 LOG_WARN("GetValue [%{private}s] failed [%{private}d]", fieldNameStr.c_str(), ret);
466 return ret;
467 }
468 return resultSet->GetString(index, out);
469 }
470
471 std::vector<std::shared_ptr<Calendar>> ResultSetToCalendars(DataShareResultSetPtr &resultSet)
472 {
473 std::vector<std::shared_ptr<Calendar>> result;
474 int rowCount = 0;
475 resultSet->GetRowCount(rowCount);
476 LOG_INFO("GetRowCount is %{public}d", rowCount);
477 if (rowCount == 0) {
478 return result;
479 }
480 auto err = resultSet->GoToFirstRow();
481 if (err != DataShare::E_OK) {
482 LOG_INFO("Failed GoToFirstRow %{public}d", err);
483 return result;
484 }
485 do {
486 int idValue = -1;
487 if (GetValue(resultSet, "_id", idValue) != DataShare::E_OK) {
488 break;
489 }
490 LOG_DEBUG("id: %{private}d", idValue);
491 std::string nameValue;
492 if (GetValue(resultSet, "account_name", nameValue) != DataShare::E_OK) {
493 break;
494 }
495 LOG_DEBUG("account_name: %{private}s", nameValue.c_str());
496 std::string typeValue;
497 if (GetValue(resultSet, "account_type", typeValue) != DataShare::E_OK) {
498 break;
499 }
500 LOG_DEBUG("account_type: %{private}s", typeValue.c_str());
501
502 std::string displayNameValue;
503 GetValue(resultSet, "calendar_displayName", displayNameValue);
504 LOG_DEBUG("calendar_displayName: %{private}s", displayNameValue.c_str());
505
506 int canReminder = -1;
507 GetValue(resultSet, "canReminder", canReminder);
508 LOG_DEBUG("canReminder: %{private}d", canReminder);
509
510 int colorValue = 0;
511 GetValue(resultSet, "calendar_color", colorValue);
512 CalendarAccount curAccount {nameValue, typeValue, displayNameValue};
513 result.emplace_back(std::make_shared<Calendar>(curAccount, idValue));
514 } while (resultSet->GoToNextRow() == DataShare::E_OK);
515 return result;
516 }
517
518 std::optional<Location> ResultSetToLocation(DataShareResultSetPtr &resultSet)
519 {
520 Location out;
521 string value;
522 double maxLon = 180;
523 double maxLat = 90;
524 auto ret = GetValue(resultSet, "eventLocation", value);
525 out.location = std::make_optional<string>(value);
526 ret = GetValue(resultSet, "location_longitude", value);
527 std::stringstream str2digit;
528 double longitudeValue = 0;
529 if (!value.empty()) {
530 str2digit << value;
531 str2digit >> longitudeValue;
532 if (fabs(longitudeValue) <= maxLon) {
533 out.longitude = std::make_optional<double>(longitudeValue);
534 }
535 }
536
537 ret = GetValue(resultSet, "location_latitude", value);
538 double latitudeValue = 0;
539 str2digit.clear();
540 if (!value.empty()) {
541 str2digit << value;
542 str2digit >> latitudeValue;
543 if (fabs(latitudeValue) <= maxLat) {
544 out.latitude = std::make_optional<double>(latitudeValue);
545 }
546 }
547
548 if (ret != DataShare::E_OK) {
549 return std::nullopt;
550 }
551 return std::make_optional<Location>(out);
552 }
553
554 std::optional<EventService> ResultSetToEventService(DataShareResultSetPtr &resultSet)
555 {
556 EventService out;
557 string value;
558 auto ret = GetValue(resultSet, "service_type", value);
559 if (ret != DataShare::E_OK) {
560 return std::nullopt;
561 }
562 const std::set<std::string> serviceType = {"Meeting", "Watching", "Repayment", "Live", "Shopping",
563 "Trip", "Class", "SportsEvents", "SportsExercise"};
564 if (serviceType.count(value)) {
565 out.type = value;
566 } else {
567 return std::nullopt;
568 }
569 ret = GetValue(resultSet, "service_cp_bz_uri", value);
570 if (ret != DataShare::E_OK) {
571 return std::nullopt;
572 }
573 out.uri = value;
574 ret = GetValue(resultSet, "service_description", value);
575 if (ret == DataShare::E_OK) {
576 out.description = std::make_optional<string>(value);
577 }
578 return std::make_optional<EventService>(out);
579 }
580
581 int StringToInt(const std::string &str)
582 {
583 try {
584 return std::stoi(str);
585 } catch (std::exception &ex) {
586 LOG_ERROR("StringToInt conversion fail, str: %{public}s", str.c_str());
587 return 0;
588 }
589 }
590
591 std::time_t TimeToUTC(const std::string &strTime)
592 {
593 const int baseYear = 1900;
594 const int offset = 2;
595 const int yearOffset = 4;
596 const int monBase = 4;
597 const int dayBase = 6;
598 const int hourBase = 9;
599 const int minBase = 11;
600 const int secBase = 13;
601 const int monCount = 12;
602 const int monRectify = 11;
603 const int micSecond = 1000;
604 const int timeStrLenMin = 8;
605 const int timeStrLen = 15;
606
607 std::tm expireTime = {0};
608 if (strTime.size() < timeStrLenMin) {
609 LOG_DEBUG("strTime length error");
610 return 0;
611 }
612 expireTime.tm_year = StringToInt(strTime.substr(0, yearOffset)) - baseYear;
613 expireTime.tm_mon = (StringToInt(strTime.substr(monBase, offset)) + monRectify) % monCount;
614 expireTime.tm_mday = StringToInt(strTime.substr(dayBase, offset));
615 if (strTime.find("T") != std::string::npos && strTime.length() >= timeStrLen) {
616 expireTime.tm_hour = StringToInt(strTime.substr(hourBase, offset));
617 expireTime.tm_min = StringToInt(strTime.substr(minBase, offset));
618 expireTime.tm_sec = StringToInt(strTime.substr(secBase, offset));
619 } else {
620 expireTime.tm_hour = 0;
621 expireTime.tm_min = 0;
622 expireTime.tm_sec = 0;
623 }
624
625 std::time_t utcTime = mktime(&expireTime) * micSecond; //精确到微秒
626
627 return utcTime;
628 }
629
630 std::vector<std::string> SplitString(const std::string &str, const std::string &flag)
631 {
632 std::vector<std::string> result;
633 std::string::size_type pos1 = 0;
634 std::string::size_type pos2 = str.find(flag);
635 while (pos2 != std::string::npos) {
636 result.push_back(str.substr(pos1, pos2 - pos1));
637 pos1 = pos2 + flag.size();
638 pos2 = str.find(flag, pos1);
639 }
640 if (pos1 != str.length()) {
641 result.push_back(str.substr(pos1));
642 }
643
644 return result;
645 }
646
647 std::optional<vector<int64_t>> ResultSetToExcludedDates(DataShareResultSetPtr &resultSet)
648 {
649 std::string value;
650 auto ret = GetValue(resultSet, "exdate", value);
651 if (ret != DataShare::E_OK) {
652 return std::nullopt;
653 }
654 std::vector<string> strListExDate = SplitString(value, ",");
655
656 std::vector<int64_t> excludedDates;
657 for (const auto &str : strListExDate) {
658 auto exDate = TimeToUTC(str);
659 excludedDates.emplace_back(exDate);
660 }
661
662 return std::make_optional<vector<int64_t>>(excludedDates);
663 }
664
665 void ConvertRecurrenceFrequency(const std::string &frequency, RecurrenceRule &rule)
666 {
667 if (frequency == "YEARLY") {
668 rule.recurrenceFrequency = YEARLY;
669 return;
670 }
671 if (frequency == "MONTHLY") {
672 rule.recurrenceFrequency = MONTHLY;
673 return;
674 }
675 if (frequency == "WEEKLY") {
676 rule.recurrenceFrequency = WEEKLY;
677 return;
678 }
679 if (frequency == "DAILY") {
680 rule.recurrenceFrequency = DAILY;
681 }
682 }
683
684 std::optional<RecurrenceRule> ResultSetToRecurrenceRule(DataShareResultSetPtr &resultSet)
685 {
686 const int strListSize = 2;
687 RecurrenceRule out;
688 out.recurrenceFrequency = NORULE;
689 std::string value;
690 auto ret = GetValue(resultSet, "rrule", value);
691 if (ret != DataShare::E_OK) {
692 return std::nullopt;
693 }
694 std::map<std::string, std::string> ruleMap;
695 std::vector<std::string> strListRule = SplitString(value, ";");
696 for (const auto &str : strListRule) {
697 std::vector<std::string> keyAndValue = SplitString(str, "=");
698 if (keyAndValue.size() == strListSize) {
699 ruleMap.insert(std::pair<std::string, std::string>(keyAndValue[0], keyAndValue[1]));
700 }
701 }
702 SetRRuleValue(ruleMap, out);
703 out.excludedDates = ResultSetToExcludedDates(resultSet);
704
705 return std::make_optional<RecurrenceRule>(out);
706 }
707
708 void SetVecNum(std::optional<std::vector<int64_t>> &ruleVec, const std::string &ruleStr)
709 {
710 std::vector<std::string> weekNumList = SplitString(ruleStr, ",");
711 for (const auto &weekNum : weekNumList) {
712 ruleVec->push_back(StringToInt(weekNum));
713 }
714 }
715
716 void SetRRuleValue(const std::map<std::string, std::string> &ruleMap, RecurrenceRule &out)
717 {
718 std::map<std::string, std::string>::const_iterator iter;
719 for (iter = ruleMap.begin(); iter != ruleMap.end(); iter++) {
720 if (iter->first == "FREQ") {
721 ConvertRecurrenceFrequency(iter->second, out);
722 continue;
723 }
724 if (iter->first == "COUNT") {
725 out.count = std::make_optional<int64_t>(StringToInt(iter->second));
726 continue;
727 }
728 if (iter->first == "INTERVAL") {
729 out.interval = std::make_optional<int64_t>(StringToInt(iter->second));
730 continue;
731 }
732 if (iter->first == "UNTIL") {
733 out.expire = std::make_optional<int64_t>(TimeToUTC(iter->second));
734 }
735 if (iter->first == "BYDAY") {
736 std::vector<std::string> weekDayList = SplitString(iter->second, ",");
737 SetByDayOfRRule(weekDayList, out);
738 }
739 if (iter->first == "BYWEEKNO") {
740 out.weeksOfYear = std::make_optional<std::vector<int64_t>>();
741 SetVecNum(out.weeksOfYear, iter->second);
742 }
743 if (iter->first == "BYMONTHDAY") {
744 out.daysOfMonth = std::make_optional<std::vector<int64_t>>();
745 SetVecNum(out.daysOfMonth, iter->second);
746 }
747 if (iter->first == "BYYEARDAY") {
748 out.daysOfYear = std::make_optional<std::vector<int64_t>>();
749 SetVecNum(out.daysOfYear, iter->second);
750 }
751 if (iter->first == "BYMONTH") {
752 out.monthsOfYear = std::make_optional<std::vector<int64_t>>();
753 SetVecNum(out.monthsOfYear, iter->second);
754 }
755 }
756 }
757
758 void SetByDayOfRRule(const std::vector<std::string> &weekDayList, RecurrenceRule &out)
759 {
760 const int weekStrLen = 2;
761 const std::vector<string> dayOfWeekList = {"MO", "TU", "WE", "TH", "FR", "SA", "SU"};
762 out.daysOfWeek = std::make_optional<vector<int64_t>>();
763 out.weeksOfMonth = std::make_optional<vector<int64_t>>();
764 for (const auto &weekday : weekDayList) {
765 if (weekday.length() > weekStrLen) {
766 std::string weekDayStr = weekday.substr(weekday.length() - weekStrLen, weekStrLen);
767 std::string WeekNumStr = weekday.substr(0, weekday.length() - weekStrLen);
768 auto it = std::find(dayOfWeekList.begin(), dayOfWeekList.end(), weekDayStr);
769 if (it != dayOfWeekList.end()) {
770 int dayNum = it - dayOfWeekList.begin();
771 out.daysOfWeek->push_back(dayNum + 1);
772 out.weeksOfMonth->push_back(StringToInt(WeekNumStr));
773 }
774 } else if (weekday.length() == weekStrLen) {
775 auto it = std::find(dayOfWeekList.begin(), dayOfWeekList.end(), weekday);
776 if (it != dayOfWeekList.end()) {
777 int dayNum = it - dayOfWeekList.begin();
778 out.daysOfWeek->push_back(dayNum + 1);
779 }
780 }
781 }
782 }
783
784 void ResultSetToInstanceTime(Event &event, DataShareResultSetPtr &resultSet, const std::set<std::string>& columns)
785 {
786 if (columns.count("instanceStartTime")) {
787 GetValueOptional(resultSet, "begin", event.instanceStartTime);
788 }
789
790 if (columns.count("instanceEndTime")) {
791 GetValueOptional(resultSet, "end", event.instanceEndTime);
792 }
793 }
794
795 void ResultSetToEvent(Event &event, DataShareResultSetPtr &resultSet, const std::set<std::string>& columns)
796 {
797 GetValueOptional(resultSet, "_id", event.id);
798 if (columns.count("type")) {
799 int type = 0;
800 GetValue(resultSet, "important_event_type", type);
801 event.type = static_cast<EventType>(type);
802 }
803 if (columns.count("title")) {
804 GetValueOptional(resultSet, "title", event.title);
805 }
806 if (columns.count("startTime")) {
807 LOG_DEBUG("TLQ get startTime");
808 GetValue(resultSet, "dtstart", event.startTime);
809 }
810 if (columns.count("endTime")) {
811 LOG_DEBUG("TLQ get endTime");
812 GetValue(resultSet, "dtend", event.endTime);
813 }
814 if (columns.count("isAllDay")) {
815 int isAllDay = 0;
816 GetValue(resultSet, "allDay", isAllDay);
817 event.isAllDay = static_cast<bool>(isAllDay);
818 }
819 if (columns.count("description")) {
820 GetValueOptional(resultSet, "description", event.description);
821 }
822 if (columns.count("timeZone")) {
823 GetValueOptional(resultSet, "eventTimezone", event.timeZone);
824 }
825 if (columns.count("location")) {
826 event.location = ResultSetToLocation(resultSet);
827 }
828 if (columns.count("service")) {
829 event.service = ResultSetToEventService(resultSet);
830 }
831 if (columns.count("recurrenceRule")) {
832 event.recurrenceRule = ResultSetToRecurrenceRule(resultSet);
833 }
834
835 if (columns.count("identifier")) {
836 GetValueOptional(resultSet, "identifier", event.identifier);
837 }
838 if (columns.count("isLunar")) {
839 int isLunar = 0;
840 GetValue(resultSet, "event_calendar_type", isLunar);
841 event.isLunar = static_cast<bool>(isLunar);
842 }
843 ResultSetToInstanceTime(event, resultSet, columns);
844 }
845
846 int ResultSetToEvents(std::vector<std::string> &eventIds, std::vector<Event> &events,
847 DataShareResultSetPtr &resultSet, const std::set<std::string>& columns)
848 {
849 int rowCount = 0;
850 resultSet->GetRowCount(rowCount);
851 LOG_INFO("GetRowCount is %{public}d", rowCount);
852 if (rowCount <= 0) {
853 return -1;
854 }
855 auto err = resultSet->GoToFirstRow();
856 if (err != DataShare::E_OK) {
857 LOG_ERROR("Failed GoToFirstRow %{public}d", err);
858 return -1;
859 }
860 do {
861 Event event;
862 ResultSetToEvent(event, resultSet, columns);
863 if (!event.id.has_value()) {
864 continue;
865 }
866 eventIds.emplace_back(std::to_string(event.id.value()));
867 events.emplace_back(event);
868 } while (resultSet->GoToNextRow() == DataShare::E_OK);
869 return 0;
870 }
871
872 void ResultSetToAttendeeStatus(Attendee &attendee, DataShareResultSetPtr &resultSet)
873 {
874 int statusValue = 0;
875 GetValue(resultSet, "attendeeStatus", statusValue);
876 if (statusValue == UNKNOWN) {
877 attendee.status = std::make_optional<AttendeeStatus>(UNKNOWN);
878 } else if (statusValue == TENTATIVE) {
879 attendee.status = std::make_optional<AttendeeStatus>(TENTATIVE);
880 } else if (statusValue == ACCEPTED) {
881 attendee.status = std::make_optional<AttendeeStatus>(ACCEPTED);
882 } else if (statusValue == DECLINED) {
883 attendee.status = std::make_optional<AttendeeStatus>(DECLINED);
884 } else {
885 attendee.status = std::make_optional<AttendeeStatus>(UNRESPONSIVE);
886 }
887 }
888
889 void ResultSetToAttendeeType(Attendee &attendee, DataShareResultSetPtr &resultSet)
890 {
891 int typeValue = 0;
892 GetValue(resultSet, "attendeeType", typeValue);
893 if (typeValue == REQUIRED) {
894 attendee.type = std::make_optional<AttendeeType>(REQUIRED);
895 } else if (typeValue == OPTIONAL) {
896 attendee.type = std::make_optional<AttendeeType>(OPTIONAL);
897 } else {
898 attendee.type = std::make_optional<AttendeeType>(RESOURCE);
899 }
900 }
901
902 int ResultSetToMultiAttendees(std::vector<Event> &events, DataShareResultSetPtr &resultSet)
903 {
904 if (!resultSet) {
905 LOG_ERROR("resultSet is null");
906 return -1;
907 }
908 int rowCount = 0;
909 resultSet->GetRowCount(rowCount);
910 LOG_INFO("GetRowCount is %{public}d", rowCount);
911 if (rowCount <= 0) {
912 return -1;
913 }
914 auto err = resultSet->GoToFirstRow();
915 if (err != DataShare::E_OK) {
916 LOG_ERROR("Failed GoToFirstRow %{public}d", err);
917 return -1;
918 }
919 std::map<int, std::vector<Attendee>> attendeesMap;
920 int roleValue = 0;
921 do {
922 Attendee attendee;
923 int eventId;
924 GetValue(resultSet, "event_id", eventId);
925 GetValue(resultSet, "attendeeName", attendee.name);
926 GetValue(resultSet, "attendeeEmail", attendee.email);
927 GetValue(resultSet, "attendeeRelationship", roleValue);
928 if (roleValue == PARTICIPANT) {
929 attendee.role = std::make_optional<RoleType>(PARTICIPANT);
930 } else if (roleValue == ORGANIZER) {
931 attendee.role = std::make_optional<RoleType>(ORGANIZER);
932 }
933
934 ResultSetToAttendeeStatus(attendee, resultSet);
935 ResultSetToAttendeeType(attendee, resultSet);
936
937 auto attendeeFindId = attendeesMap.find(eventId);
938 if (attendeeFindId == attendeesMap.end()) {
939 attendeesMap.insert(std::pair<int, std::vector<Attendee>>(eventId, {attendee}));
940 } else {
941 attendeeFindId->second.emplace_back(attendee);
942 }
943 } while (resultSet->GoToNextRow() == DataShare::E_OK);
944 GetEventAttendeesValue(events, attendeesMap);
945 return 0;
946 }
947
948 void GetEventAttendeesValue(std::vector<Event> &events, const std::map<int, std::vector<Attendee>> &attendeesMap) {
949 if (attendeesMap.size() == 0) {
950 LOG_ERROR("attendees has no value");
951 return;
952 }
953 for (auto &event : events) {
954 const auto id = event.id;
955 if (!id) {
956 LOG_ERROR("event id is null");
957 continue;
958 }
959 auto attendeeFindId = attendeesMap.find(id.value());
960 if (attendeeFindId != attendeesMap.end()) {
961 event.attendees = attendeeFindId->second;
962 }
963 }
964 }
965
966 std::string EventIdsToString(const std::vector<int> &ids) {
967 if (ids.empty()) {
968 return "";
969 }
970 return std::accumulate(std::next(ids.begin()), ids.end(), std::to_string(ids[0]),
971 [](const std::string& a, int b) {
972 std::stringstream ss;
973 ss << a << ", " << b;
974 return ss.str();
975 }
976 );
977 }
978
979 int ResultSetToMultiReminders(std::vector<Event> &events, DataShareResultSetPtr &resultSet)
980 {
981 if (!resultSet) {
982 LOG_ERROR("resultSet is null");
983 return -1;
984 }
985 int rowCount = 0;
986 resultSet->GetRowCount(rowCount);
987 LOG_INFO("GetRowCount is %{public}d", rowCount);
988 if (rowCount <= 0) {
989 return -1;
990 }
991 auto err = resultSet->GoToFirstRow();
992 if (err != DataShare::E_OK) {
993 LOG_ERROR("Failed GoToFirstRow %{public}d", err);
994 return -1;
995 }
996 std::map<int, std::vector<int>> remindersMap;
997 do {
998 int minutes = 0;
999 int eventId = 0;
1000 GetValue(resultSet, "minutes", minutes);
1001 GetValue(resultSet, "event_id", eventId);
1002 auto eventFindId = remindersMap.find(eventId);
1003 if (eventFindId == remindersMap.end()) {
1004 remindersMap.insert(std::pair<int, std::vector<int>>(eventId, {minutes}));
1005 } else {
1006 eventFindId->second.emplace_back(minutes);
1007 }
1008 } while (resultSet->GoToNextRow() == DataShare::E_OK);
1009 if (remindersMap.size() == 0) {
1010 LOG_ERROR("reminders has no value");
1011 return -1;
1012 }
1013 for (auto &event : events) {
1014 const auto id = event.id;
1015 if (!id) {
1016 LOG_ERROR("event id is null");
1017 continue;
1018 }
1019 auto eventFindId = remindersMap.find(id.value());
1020 if (eventFindId != remindersMap.end()) {
1021 event.reminderTime = eventFindId->second;
1022 }
1023 }
1024 return 0;
1025 }
1026
1027 void ResultSetToConfig(CalendarConfig &config, DataShareResultSetPtr &resultSet)
1028 {
1029 int rowCount = 0;
1030 resultSet->GetRowCount(rowCount);
1031 LOG_INFO("GetRowCount is %{public}d", rowCount);
1032 auto err = resultSet->GoToFirstRow();
1033 if (err != DataShare::E_OK) {
1034 LOG_ERROR("Failed GoToFirstRow %{public}d", err);
1035 }
1036 do {
1037 int enableReminder = 0;
1038 std::int64_t color = 0;
1039 GetValue(resultSet, "canReminder", enableReminder);
1040 GetValue(resultSet, "calendar_color", color);
1041 config.enableReminder = static_cast<bool>(enableReminder);
1042 LOG_INFO("enableReminder is %{public}d", enableReminder);
1043 config.color = color;
1044 } while (resultSet->GoToNextRow() == DataShare::E_OK);
1045 }
1046
1047 bool IsValidHexString(const std::string& colorStr)
1048 {
1049 if (colorStr.empty()) {
1050 return false;
1051 }
1052 for (char ch : colorStr) {
1053 if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
1054 continue;
1055 }
1056 return false;
1057 }
1058 return true;
1059 }
1060
1061 bool ColorParse(const std::string& colorStr, variant<string, int64_t>& colorValue)
1062 {
1063 if (colorStr.empty()) {
1064 LOG_ERROR("color string is empty");
1065 return false;
1066 }
1067
1068 if (colorStr[0] != '#') { // start with '#'
1069 LOG_ERROR("color string not start with #");
1070 return false;
1071 }
1072
1073 const int rgbLen = 7;
1074 const int argbLen = 9;
1075 if (colorStr.size() != rgbLen && colorStr.size() != argbLen) {
1076 LOG_ERROR("color string length is not 7 or 9");
1077 return false;
1078 }
1079
1080 std::string colorStrSub = colorStr.substr(1);
1081 if (!IsValidHexString(colorStrSub)) {
1082 LOG_DEBUG("color string is not valid hex string");
1083 return false;
1084 }
1085
1086 LOG_DEBUG("color string size is 7 or 9");
1087 try {
1088 colorValue.emplace<1>(std::stoll(colorStrSub, NULL, 16)); // 16 is convert hex string to number
1089 } catch (std::exception &ex) {
1090 LOG_ERROR("stoll fail %{public}s", ex.what());
1091 return false;
1092 }
1093 if (std::get_if<1>(&colorValue)) {
1094 LOG_DEBUG("colorStrSub -> colorValue colorValue:%{public}s", std::to_string(std::get<1>(colorValue)).c_str());
1095 return true;
1096 }
1097 LOG_DEBUG("color is null");
1098 return false;
1099 }
1100
1101 void SetLocationFieldInfo(std::vector<string>& queryField)
1102 {
1103 queryField.emplace_back("eventLocation");
1104 queryField.emplace_back("location_longitude");
1105 queryField.emplace_back("location_latitude");
1106 }
1107
1108 void SetServiceFieldInfo(std::vector<string>& queryField)
1109 {
1110 queryField.emplace_back("service_type");
1111 queryField.emplace_back("service_cp_bz_uri");
1112 queryField.emplace_back("service_description");
1113 }
1114
1115 void FillFieldInfo(const std::string field, std::vector<string>& queryField, std::set<string>& resultSetField,
1116 const std::map<string, string> eventField)
1117 {
1118 if (field == "location") {
1119 SetLocationFieldInfo(queryField);
1120 resultSetField.insert(field);
1121 return;
1122 }
1123 if (field == "service") {
1124 SetServiceFieldInfo(queryField);
1125 resultSetField.insert(field);
1126 return;
1127 }
1128 if (field == "attendee") {
1129 resultSetField.insert(field);
1130 return;
1131 }
1132 if (field == "reminderTime") {
1133 resultSetField.insert(field);
1134 return;
1135 }
1136 if (field == "identifier") {
1137 queryField.emplace_back("identifier");
1138 resultSetField.insert(field);
1139 return;
1140 }
1141 if (field == "recurrenceRule") {
1142 queryField.emplace_back("rrule");
1143 queryField.emplace_back("exdate");
1144 resultSetField.insert(field);
1145 return;
1146 }
1147 if (field == "isLunar") {
1148 queryField.emplace_back("event_calendar_type");
1149 resultSetField.insert(field);
1150 return;
1151 }
1152 if (field == "instanceStartTime") {
1153 queryField.emplace_back("begin");
1154 resultSetField.insert(field);
1155 return;
1156 }
1157 if (field == "instanceEndTime") {
1158 queryField.emplace_back("end");
1159 resultSetField.insert(field);
1160 return;
1161 }
1162 queryField.emplace_back(eventField.at(field));
1163 resultSetField.insert(field);
1164 }
1165
1166 void SetFieldInfo(const std::vector<string>& eventKey, std::vector<string>& queryField,
1167 std::set<string>& resultSetField, const std::map<string, string> eventField)
1168 {
1169 for (const auto& field : eventKey) {
1170 if (field == "id") {
1171 continue;
1172 }
1173 FillFieldInfo(field, queryField, resultSetField, eventField);
1174 }
1175 }
1176
1177 void SetField(const std::vector<string>& eventKey, std::vector<string>& queryField, std::set<string>& resultSetField)
1178 {
1179 const std::map<string, string> eventField = { { "id", "_id" },
1180 { "type", "important_event_type" },
1181 { "title", "title" },
1182 { "startTime", "dtstart" },
1183 { "endTime", "dtend" },
1184 { "isAllDay", "allDay" },
1185 { "timeZone", "eventTimezone" },
1186 { "description", "description" }};
1187 SetFieldInfo(eventKey, queryField, resultSetField, eventField);
1188 }
1189 }