Fork HTTPClient and Modfiy code for mbed 6.0

Dependents:   mbed-demo-http-get-json

data/HTTPiCal.h

Committer:
quxiaorui
Date:
2020-11-08
Revision:
51:a9ed5a6eee90
Parent:
40:bcb19f8dbba3

File content as of revision 51:a9ed5a6eee90:

#ifndef HTTPICAL_H
#define HTTPICAL_H
#include <mbed.h>
#include "../IHTTPData.h"


/// An iCal handling mechanism - downloads and parses calendar events
class HTTPiCal : public IHTTPDataIn {
    
    public:
        #define SUMMARY_CHARS 100
        #define LOCATION_CHARS 100
        #define CATEGORY_CHARS 20
        #define LINEBUFLEN 200
        
        /// The repeat attribute for an event
        typedef enum {
            rptfNone,                       ///< no repeat for this event
            rptfDaily,                      ///< daily repeat
            rptfWeekly,                     ///< weekly repeat
            rptfMonthly,                    ///< monthly repeat
            rptfYearly                      ///< yearly repeat
        } RepeatFreq_t;

        typedef int32_t tz_sec_t;
        typedef int16_t tz_min_t;

        /// A single event consists of quite a number of attributes.
        typedef struct {
            time_t Start;
            time_t End;
            time_t Until;
            uint16_t Count;
            uint16_t Interval;
            RepeatFreq_t RepeatFreq;
            uint8_t RepeatDays;             // bit mapped (bit 0 = sunday, bit 1=monday, ...)
            uint16_t RepeatMonths;          // bit mapped (bit 0 = jan, 1=feb, ...)
            uint32_t RepeatMonthDay;        // bit mapped (bit 1 = 1st, 2=2nd, ...)
            uint32_t RepeatMonthDayRev;     // reverse -1 = last day = bit 1, -2=bit 2, ...
            char Summary[SUMMARY_CHARS];
            char Location[LOCATION_CHARS];
            char Category[CATEGORY_CHARS];  // "Green", ...
            int Priority;                   // 1 == High, 5 == Normal, 9 == Low
        } Event_T;
        

        /// Instantiate HTTPiCal 
        ///
        /// @code
        /// HTTPClient http;
        /// HTTPiCal iCal(10);      // define a limit of 10 events to be held
        ///
        /// http.basicAuth(calInfo.user, calInfo.pass);
        ///
        /// time_t now = t.timelocal();     // Set a 4-hour window from now
        /// time_t nxt = now + 4 * 3600;
        /// ical.SetTimeWindow(now, nxt);
        /// HTTPErrorCode = http.get(calInfo.url, &iCal);
        /// if (HTTPErrorCode == HTTP_OK) {
        ///     // calendar successfully downloaded
        ///     for (int i=0; i<iCal.GetEventCount(); i++) {
        ///        HTTPiCal::Event_T event;
        ///        if (ical.GetEvent(i, &event)) {
        ///            printf("Event %d\r\n", i);
        ///            printf("Summary : %s\r\n", event.Summary);
        ///            printf("Location: %s\r\n", event.Location);
        ///            printf("Category: %s\r\n", event.Category);
        ///        }
        ///     }
        /// }
        /// @endcode
        ///
        /// @param count is the number of Event_T entries to reserve space for.
        ///
        HTTPiCal(int count);
        
        /// Destructor to free memory
        ~HTTPiCal();
        
        /// Set the time window of interest, for which to retain events.
        ///
        /// This sets the time window of interest. Any event, whether directly 
        /// scheduled in this window, or indirectly via repeat attributes, will
        /// be retained in the list of available events. Any event not in this
        /// window will be ignored.
        ///
        /// @param StartTime is the optional time value for the beginning of 
        ///         interest. If gridStartTime is zero, no filtering is performed.
        /// @param EndTime is the optional time value ending the period of interest.
        ///
        void SetTimeWindow(time_t StartTime = 0, time_t EndTime = 0);
 
        /// Get the count of Events currently available.
        ///
        /// @returns the count of events.
        ///
        int GetEventCount(void) { return EventCount; }
        
        /// Get a copy of the specified event.
        ///
        /// @param i is the event number, ranging from 0 to GetEventCount()
        /// @param event is a pointer to where the event will be copied.
        /// @returns true if the event was available and copied.
        ///
        bool GetEvent(unsigned int i, Event_T * event);


        /// Compute the intersection of two time ranges, and evaluate the recurringing events.
        ///
        /// This compares a pair of time ranges, each by a start and end time. If they overlap
        /// it then computes the intersection of those two ranges. Additionally, for a 
        /// specified Event, it will evaluate the recurring events that may also fall into
        /// the target time range.
        ///
        /// @note This is usually the only API you need, as this will first call
        ///     the TimeIntersects function, and if that fails, then it will evaluate
        ///     repeat information.
        ///
        /// @param[in,out] start1 is the starting time of range 1.
        /// @param[in,out] end1 is the ending time of range 1.
        /// @param[in] start2 is the starting time of range 2.
        /// @param[in] end2 is the ending time of range 2.
        /// @param[in] Event is a pointer to the event of interest that may have recurring series.
        /// @returns true if the ranges overlap, and then start1 and end1 are set to the
        ///     intersection.
        ///
        bool RepeatIntersects(time_t * start1, time_t * end1, time_t * start2, time_t * end2, Event_T * Event = NULL);
        
        
        /// Compute the intersection of two time ranges, and returns that intersection.
        ///
        /// This compares a pair of time ranges, each by a start and end time. If they overlap
        /// it then computes the intersection of those two ranges.
        ///
        /// @param[in,out] start1 is the starting time of range 1.
        /// @param[in,out] end1 is the ending time of range 1.
        /// @param[in] start2 is the starting time of range 2.
        /// @param[in] end2 is the ending time of range 2.
        /// @returns true if the ranges overlap, and then start1 and end1 are set to the
        ///     intersection.
        ///
        bool TimeIntersects(time_t * start1, time_t * end1, time_t * start2, time_t * end2);


    protected:     
       
        friend class HTTPClient;
    
        /** Reset stream to its beginning 
        * Called by the HTTPClient on each new request
        */
        virtual void writeReset();
        
        /** Write a piece of data transmitted by the server
        * @param[in] buf Pointer to the buffer from which to copy the data
        * @param[in] len Length of the buffer
        * @returns number of bytes written.
        */
        virtual int write(const char* buf, size_t len);
        
        /** Set MIME type
        * @param[in] type Internet media type from Content-Type header
        */
        virtual void setDataType(const char* type);
        
        /** Determine whether the data is chunked
        *  Recovered from Transfer-Encoding header
        * @param[in] chunked indicates the transfer is chunked.
        */
        virtual void setIsChunked(bool chunked);
        
        /** If the data is not chunked, set its size
        * From Content-Length header
        * @param[in] len defines the size of the non-chunked transfer.
        */
        virtual void setDataLen(size_t len);

    private:
        char lineBuf[LINEBUFLEN];      ///< workspace to copy [partial] lines into
    
        Event_T * EventList;    ///< Pointer to the array of events
        int EventSpaceCount;    ///< Maximum number of events that can be tracked
        int EventCount;         ///< Current Count of events 

        time_t gridStartTime;   ///< defines the start of the time window of interest
        time_t gridEndTime;     ///< defines the end of the time winedow of interest

        int32_t tzoTZIDSec;
        bool tzAdjusted;
        
        typedef enum { 
            idle, 
            inTimeZone, 
            inEvent 
        } seekstate_t;
        seekstate_t seeking;

        #if !defined(min) && !defined(max)
        #define min(a,b) (((a)<(b))?(a):(b))
        #define max(a,b) (((a)>(b))?(a):(b))
        #endif
        
        /// Determine if a specific timestamp is in a leap year
        ///
        /// @param[in] t is the timestamp to evaluate
        /// @returns true if the specified timestamp is within a leap year
        ///
        bool isLeapYear(time_t t);

        /// Inspect the event to determine if its repeat attribute places it in the specified time window
        ///
        /// @param[in] start1 represents the start of the timerange of interest.
        /// @param[in] end1 is the time range representing the end of the range of interest
        /// @param[in] start2 is the time range of the event being tested
        /// @param[in] end2 is the time range of the event being tested
        /// @param[in] Event is a pointer to the event being tested and permits testing the repeat information.
        /// @returns true if the event repeat pattern intersects with the display pattern
        ///
        bool RepeatMaskIntersects(time_t * start1, time_t * end1, time_t * start2, time_t * end2, Event_T * Event);

        /// Convert 'n' characters in a string to an unsigned integer.
        ///
        /// @param[in] p is a pointer to the string.
        /// @param[in] n is the number of characters to convert.
        /// @returns an unsigned integer of the converted value.
        ///
        uint16_t AtoIxN(const char * p, int n);

        /// Parse some information from the stream and extract event information.
        ///
        /// @param[in] Event is a pointer to the current event to populate.
        /// @param[in] pStart is a pointer to the start of a text stream to evaluate.
        /// @param[in] tzoSec is the time zone offset in seconds.
        ///
        void ParseEvent(Event_T * Event, const char * pStart, tz_sec_t tzoSec);
        
        
        /// Prepare to start processing an iCal stream
        ///
        /// This initializes the data structures for parsing.
        ///
        /// @code
        /// ParseICalStart();
        /// while (receive(buf, ... ))
        ///     ParseICalStream(buf, ...);
        /// count = ParseICalClose();
        /// @endcode
        ///
        void ParseICalStart(void);
        
        
        /// End processing an iCal stream and return the number of events
        ///
        /// @returns number of events in range
        ///
        int ParseICalClose(void);
        
        
        /// Parse an iCal stream, and extract everything useful.
        ///
        /// This accepts a pointer to a [large] buffer, which is the contents
        /// of an iCal stream. It walked through all of the available
        /// information to extract the Event list. 
        ///
        /// @param[in] pStart is a pointer to the start of the stream.
        /// @param[in] gridStartTime is a time value representing the start of the time-window of interest.
        /// @param[in] gridEndTime is a time value representing the end of the time-window of interest.
        /// @param[in] tzoMin is the time-zone offset in minutes.
        /// @param[in] showEvents when true causes it to print the events as parsed.
        /// @returns number of events in range.
        ///
        int ParseICalStream(const char * pStart, time_t gridStartTime, time_t gridEndTime, tz_min_t tzoMin, bool showEvents = true);


        /// Compute if the referenced event occurs within the specified time window.
        ///
        /// @param[in] startWindow is the starting timestamp.
        /// @param[in] endWindow is the ending timestamp.
        /// @param[in] Event is a pointer to the event, which can have repeat rules.
        /// @returns true if the event laps into the current time window.
        ///
//        bool EventIntersects(time_t startWindow, time_t endWindow, Event_T * Event);


        // Private Functions - no real value external to the iCal public interface
        // other than for test code.
        
        /// Computes the next interval for iCal events that have recurrence.
        /// 
        /// @param[in] baseT is the base time value which is a factor only in leap-year.
        /// @param[in] repeatFreq is a value representing the frequency of recurrence - 
        ///     0=none, 1=daily, 2=weekly, 3=monthly, 4=yearly
        /// @param[in] interval is the multiplier of that repeat frequency to the next
        ///     event.
        /// @returns a time_t value which is the incremental interval, and would be added
        ///     to a reference time.
        ///
        time_t NextInterval(time_t baseT, int repeatFreq, int interval);
        
        
        /// Format a ctime value as a string, without the trailing <cr>
        ///
        /// This uses the normal ctime function, which appends a <cr>, but
        /// it then removes that trailing line ending character. Additionally,
        /// this keeps a few local static buffers to return the time string in
        /// which permits a printf (for example) to call this api a few times
        /// and get the proper representation of each.
        ///
        /// @param[in] t is a time value;
        /// @returns a pointer to a static buffer containing the converted time.
        ///
        char * FormatCTime(time_t t);
        
        /// Sort the Events that have been extracted from the iCal results.
        ///
        void SortEvents();
        
        /// Show the details for a specific Event, on the specified serial stream.
        ///
        /// Most useful during development, and perhaps no value after that.
        ///
        /// @param[in] Event is the event of interest.
        ///
        void ShowEventInfo(Event_T & Event);
        
        /// Access the 2-letter abbreviation for the day of the week.
        /// 
        /// @param[in] i is the day of the week, where 0 = sunday
        /// @returns a pointer to the 2-letter abbreviation.
        ///
        const char * RepeatDayAbbrev(int i);
        
        /// Parse a Datestamp string into a time value.
        ///
        /// Parses a string which can look like this: 20140505T200000
        /// into a time_t value.
        ///
        /// @param[in] string is the string to parse.
        /// @param[in] tzoSec is the time-zone offset in seconds.
        /// @returns time_t value.
        ///
        time_t ParseDateStamp(const char * string, tz_sec_t tzoSec);
        
        /// Parse a Time Zone ID value from the front-end of a Datestamp
        ///
        /// Parses a string which can look like one of these:
        /// @li TZID="(GMT -06:00)":20140519T063000
        /// @li TZID:(UTC-06:00) Central Time (US & Canada)
        /// @li TZID:(GMT -06:00)
        ///
        /// @param[in] string to be parsed.
        /// @returns time zone offset in seconds.
        ///
        tz_sec_t ParseTZID(const char * string);


        bool m_chunked;
};
#endif  // HTTPICAL_H