summaryrefslogtreecommitdiff
path: root/src/libical/icalrecur.h
blob: 2ae9c02d1c1f2ebfb73d1cb2fa3074a67a9cbfdd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
/*======================================================================
 FILE: icalrecur.h
 CREATOR: eric 20 March 2000

 (C) COPYRIGHT 2000, Eric Busboom <eric@civicknowledge.com>

 This library is free software; you can redistribute it and/or modify
 it under the terms of either:

    The LGPL as published by the Free Software Foundation, version
    2.1, available at: https://www.gnu.org/licenses/lgpl-2.1.html

 Or:

    The Mozilla Public License Version 2.0. You may obtain a copy of
    the License at https://www.mozilla.org/MPL/
========================================================================*/

/**
@file icalrecur.h
@brief Routines for dealing with recurring time

How to use:

1) Get a rule and a start time from a component

@code
        icalproperty rrule;
        struct icalrecurrencetype recur;
        struct icaltimetype dtstart;

        rrule = icalcomponent_get_first_property(comp,ICAL_RRULE_PROPERTY);
        recur = icalproperty_get_rrule(rrule);
        start = icalproperty_get_dtstart(dtstart);
@endcode

Or, just make them up:

@code
        recur = icalrecurrencetype_from_string("FREQ=YEARLY;BYDAY=SU,WE");
        dtstart = icaltime_from_string("19970101T123000")
@endcode

2) Create an iterator

@code
        icalrecur_iterator *ritr;
        ritr = icalrecur_iterator_new(recur,start);
@endcode

3) Iterator over the occurrences

@code
        struct icaltimetype next;
        while (next = icalrecur_iterator_next(ritr)
               && !icaltime_is_null_time(next){
                Do something with next
        }
@endcode

Note that the time returned by icalrecur_iterator_next is in
whatever timezone that dtstart is in.

*/

#ifndef ICALRECUR_H
#define ICALRECUR_H

#include "libical_ical_export.h"
#include "icalarray.h"
#include "icaltime.h"

/*
 * Recurrence enumerations
 */

typedef enum icalrecurrencetype_frequency
{
    /* These enums are used to index an array, so don't change the
       order or the integers */

    ICAL_SECONDLY_RECURRENCE = 0,
    ICAL_MINUTELY_RECURRENCE = 1,
    ICAL_HOURLY_RECURRENCE = 2,
    ICAL_DAILY_RECURRENCE = 3,
    ICAL_WEEKLY_RECURRENCE = 4,
    ICAL_MONTHLY_RECURRENCE = 5,
    ICAL_YEARLY_RECURRENCE = 6,
    ICAL_NO_RECURRENCE = 7
} icalrecurrencetype_frequency;

typedef enum icalrecurrencetype_weekday
{
    ICAL_NO_WEEKDAY,
    ICAL_SUNDAY_WEEKDAY,
    ICAL_MONDAY_WEEKDAY,
    ICAL_TUESDAY_WEEKDAY,
    ICAL_WEDNESDAY_WEEKDAY,
    ICAL_THURSDAY_WEEKDAY,
    ICAL_FRIDAY_WEEKDAY,
    ICAL_SATURDAY_WEEKDAY
} icalrecurrencetype_weekday;

typedef enum icalrecurrencetype_skip
{
    ICAL_SKIP_BACKWARD = 0,
    ICAL_SKIP_FORWARD,
    ICAL_SKIP_OMIT,
    ICAL_SKIP_UNDEFINED
} icalrecurrencetype_skip;

enum icalrecurrence_array_max_values
{
    ICAL_RECURRENCE_ARRAY_MAX = 0x7f7f,
    ICAL_RECURRENCE_ARRAY_MAX_BYTE = 0x7f
};

/*
 * Recurrence enumerations conversion routines.
 */

LIBICAL_ICAL_EXPORT icalrecurrencetype_frequency icalrecur_string_to_freq(const char *str);
LIBICAL_ICAL_EXPORT const char *icalrecur_freq_to_string(icalrecurrencetype_frequency kind);

LIBICAL_ICAL_EXPORT icalrecurrencetype_skip icalrecur_string_to_skip(const char *str);
LIBICAL_ICAL_EXPORT const char *icalrecur_skip_to_string(icalrecurrencetype_skip kind);

LIBICAL_ICAL_EXPORT const char *icalrecur_weekday_to_string(icalrecurrencetype_weekday kind);
LIBICAL_ICAL_EXPORT icalrecurrencetype_weekday icalrecur_string_to_weekday(const char *str);

/**
 * Recurrence type routines
 */

/* See RFC 5545 Section 3.3.10, RECUR Value, and RFC 7529
 * for an explanation of the values and fields in struct icalrecurrencetype.
 *
 * The maximums below are based on lunisolar leap years (13 months)
 */
#define ICAL_BY_SECOND_SIZE     62      /* 0 to 60 */
#define ICAL_BY_MINUTE_SIZE     61      /* 0 to 59 */
#define ICAL_BY_HOUR_SIZE       25      /* 0 to 23 */
#define ICAL_BY_MONTH_SIZE      14      /* 1 to 13 */
#define ICAL_BY_MONTHDAY_SIZE   32      /* 1 to 31 */
#define ICAL_BY_WEEKNO_SIZE     56      /* 1 to 55 */
#define ICAL_BY_YEARDAY_SIZE    386     /* 1 to 385 */
#define ICAL_BY_SETPOS_SIZE     ICAL_BY_YEARDAY_SIZE          /* 1 to N */
#define ICAL_BY_DAY_SIZE        7*(ICAL_BY_WEEKNO_SIZE-1)+1   /* 1 to N */

/** Main struct for holding digested recurrence rules */
struct icalrecurrencetype
{
    icalrecurrencetype_frequency freq;

    /* until and count are mutually exclusive. */
    struct icaltimetype until;
    int count;

    short interval;

    icalrecurrencetype_weekday week_start;

    /* The BY* parameters can each take a list of values. Here I
     * assume that the list of values will not be larger than the
     * range of the value -- that is, the client will not name a
     * value more than once.

     * Each of the lists is terminated with the value
     * ICAL_RECURRENCE_ARRAY_MAX unless the list is full.
     */

    short by_second[ICAL_BY_SECOND_SIZE];
    short by_minute[ICAL_BY_MINUTE_SIZE];
    short by_hour[ICAL_BY_HOUR_SIZE];
    short by_day[ICAL_BY_DAY_SIZE];             /**< @brief Encoded value
        *
        * The 'day' element of the by_day array is encoded to allow
        * representation of both the day of the week ( Monday, Tuesday), but
        * also the Nth day of the week (first Tuesday of the month, last
        * Thursday of the year).
        *
        * These values are decoded by icalrecurrencetype_day_day_of_week() and
        * icalrecurrencetype_day_position().
        */
    short by_month_day[ICAL_BY_MONTHDAY_SIZE];
    short by_year_day[ICAL_BY_YEARDAY_SIZE];
    short by_week_no[ICAL_BY_WEEKNO_SIZE];
    short by_month[ICAL_BY_MONTH_SIZE];         /**< @brief Encoded value
        *
        * The 'month' element of the by_month array is encoded to allow
        * representation of the "L" leap suffix (RFC 7529).
        *
        * These values are decoded by icalrecurrencetype_month_is_leap()
        * and icalrecurrencetype_month_month().
        */
    short by_set_pos[ICAL_BY_SETPOS_SIZE];

    /* For RSCALE extension (RFC 7529) */
    char *rscale;
    icalrecurrencetype_skip skip;
};

#define ICALRECURRENCETYPE_INITIALIZER {                    \
    ICAL_NO_RECURRENCE,                  /* freq         */ \
    ICALTIMETYPE_INITIALIZER,            /* until        */ \
    0,                                   /* count        */ \
    1,                                   /* interval     */ \
    ICAL_MONDAY_WEEKDAY,                 /* week_start   */ \
    { ICAL_RECURRENCE_ARRAY_MAX_BYTE },  /* by_second    */ \
    { ICAL_RECURRENCE_ARRAY_MAX_BYTE },  /* by_minute    */ \
    { ICAL_RECURRENCE_ARRAY_MAX_BYTE },  /* by_hour      */ \
    { ICAL_RECURRENCE_ARRAY_MAX_BYTE },  /* by_day       */ \
    { ICAL_RECURRENCE_ARRAY_MAX_BYTE },  /* by_month_day */ \
    { ICAL_RECURRENCE_ARRAY_MAX_BYTE },  /* by_year_day  */ \
    { ICAL_RECURRENCE_ARRAY_MAX_BYTE },  /* by_week_no   */ \
    { ICAL_RECURRENCE_ARRAY_MAX_BYTE },  /* by_month     */ \
    { ICAL_RECURRENCE_ARRAY_MAX_BYTE },  /* by_set_pos   */ \
    NULL,                                /* rscale       */ \
    ICAL_SKIP_OMIT                       /* skip         */ \
}

LIBICAL_ICAL_EXPORT int icalrecurrencetype_rscale_is_supported(void);

LIBICAL_ICAL_EXPORT icalarray *icalrecurrencetype_rscale_supported_calendars(void);

LIBICAL_ICAL_EXPORT void icalrecurrencetype_clear(struct icalrecurrencetype *r);

/*
 * Routines to decode the day values of the by_day array
 */

/** @brief Decodes a day to a weekday.
 *
 * @returns The decoded day of the week. 1 is Monday, 2 is Tuesday, etc.
 * A position of 0 means 'any' or 'every'.
 *
 * The 'day' element of icalrecurrencetype_weekday is encoded to
 * allow representation of both the day of the week ( Monday, Tuesday),
 * but also the Nth day of the week ( First tuesday of the month, last
 * thursday of the year) These routines decode the day values.
 *
 * The day's position in the period ( Nth-ness) and the numerical
 * value of the day are encoded together as: pos*7 + dow.
 */
LIBICAL_ICAL_EXPORT enum icalrecurrencetype_weekday icalrecurrencetype_day_day_of_week(short day);

/** @brief Decodes a day to a position of the weekday.
 *
 * @returns The position of the day in the week.
 * 0 == any of day of week. 1 == first, 2 = second, -2 == second to last, etc.
 * 0 means 'any' or 'every'.
 */
LIBICAL_ICAL_EXPORT int icalrecurrencetype_day_position(short day);

/*
 * Routines to decode the 'month' element of the by_month array
 */

LIBICAL_ICAL_EXPORT int icalrecurrencetype_month_is_leap(short month);

LIBICAL_ICAL_EXPORT int icalrecurrencetype_month_month(short month);

/*
 * Recurrence rule parser
 */

/** Convert between strings and recurrencetype structures. */
LIBICAL_ICAL_EXPORT struct icalrecurrencetype icalrecurrencetype_from_string(const char *str);

LIBICAL_ICAL_EXPORT char *icalrecurrencetype_as_string(struct icalrecurrencetype *recur);

LIBICAL_ICAL_EXPORT char *icalrecurrencetype_as_string_r(struct icalrecurrencetype *recur);

/*
 * Recurrence iteration routines
 */

typedef struct icalrecur_iterator_impl icalrecur_iterator;

/** Creates a new recurrence rule iterator, starting at DTSTART. */
LIBICAL_ICAL_EXPORT icalrecur_iterator *icalrecur_iterator_new(struct icalrecurrencetype rule,
                                                               struct icaltimetype dtstart);

/**
 * Sets the date-time at which the iterator will start,
 * where @p start is a value between DTSTART and UNTIL.
 *
 * NOTE: CAN NOT be used with RRULEs that contain COUNT.
 * @since 3.0
 */
LIBICAL_ICAL_EXPORT int icalrecur_iterator_set_start(icalrecur_iterator *impl,
                                                     struct icaltimetype start);

/** Gets the next occurrence from an iterator. */
LIBICAL_ICAL_EXPORT struct icaltimetype icalrecur_iterator_next(icalrecur_iterator *);

/** Frees the iterator. */
LIBICAL_ICAL_EXPORT void icalrecur_iterator_free(icalrecur_iterator *);

/** @brief Fills an array with the 'count' number of occurrences generated by
 * the rrule.
 *
 * Specifically, this fills @p array up with at most 'count' time_t values, each
 * representing an occurrence time in seconds past the POSIX epoch.
 *
 * Note that the times are returned in UTC, but the times
 * are calculated in local time. You will have to convert the results
 * back into local time before using them.
 */
LIBICAL_ICAL_EXPORT int icalrecur_expand_recurrence(const char *rule, time_t start,
                                                    int count, time_t *array);

#endif