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