Page 1 of 1

Get Calendar events

Posted: Sat Nov 05, 2016 11:20 pm
by WilliamL
I wondered how difficult it would be to get the events that are in the 'Calendar' program that Apple provides.

I cannibalized another program I had and used Fred's directory scanning example and put this together to try it. You will have to change the path to your Library file in line 186 to your path.

[edited]

Code: Select all

EnableExplicit
Global avers.s=".1 (5.50x64)"
#menuhgth=50
#bom=#PB_Ascii ; #PB_UTF8

Enumeration 1
    #HskpngWnd
    #ShowCalWnd
    #ShowIcsWnd
    #ShowDayWnd
    
    #MaxWnds
EndEnumeration

;efids
    #HskpngEfid=1 ; 1
    #ShowCalEfid=#HskpngEfid+1 ; 1
    #ShowIcsEfid=#ShowCalEfid+1 ; 1
    #ShowDayEfid=#ShowIcsEfid+1  ; 1
    
Enumeration 1 ; menus
    #menuload
    #menusave
    #menushowcal
    #menushowics
    #menuShowDay
EndEnumeration

#maxevents=240
Global calcnt=20
Global Dim CalFolder$(calcnt)
Global icscnt
Global Dim CalEvents$(#maxevents)

Structure evntdata
    file.s ; full path to day file
    date.s
    time.s
    desc.s
EndStructure
Global Dim DayEvent.evntdata(#maxevents)

Procedure stop(err$)
  If MessageRequester("A stop is encountered...",err$+Chr(13)+"Do you want To quit?",#PB_MessageRequester_YesNo)=#PB_MessageRequester_Yes:End:EndIf
EndProcedure

Procedure SetUpMenus(mwnd)
    If CreateMenu(mwnd, WindowID(mwnd))
        MenuItem(#PB_Menu_About,"StmntToTextToBks (vers"+avers+")")
        MenuItem(#PB_Menu_Quit,"Quit"+Chr(9)+"Cmd+Q")
        
        MenuTitle("File")
        MenuItem(#menuload,"Load calendar data")

        MenuTitle("Show lists")
        MenuItem(#menushowcal,"Show calendar folders")
        MenuItem(#menushowics,"Show ics files")
        MenuItem(#menushowday,"Show day data")
    EndIf
EndProcedure

Procedure CloseAllWnds()
    Protected cnt
    ;don't close wind=1 it is Hskeeping and has menus
    For cnt=2 To #MaxWnds
        If IsWindow(cnt)
            CloseWindow(cnt)
        EndIf
    Next
EndProcedure

Procedure ShowCalendarFolders()
    Protected lh,h,w,cnt,a$
    lh=19
    h=calcnt*lh:If h>DesktopHeight(0)-#menuhgth:h=DesktopHeight(0)-#menuhgth:EndIf
    w=DesktopWidth(0)-30
    If OpenWindow(#ShowCalWnd,0,0,w,h,"Show calendar folders",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
        ListViewGadget(#ShowCalEfid,4,4,w-8,h-8)
        For cnt=1 To calcnt
            a$=Str(cnt)+" >"+CalFolder$(cnt)+"<"
            AddGadgetItem(#ShowCalEfid,-1,a$)
        Next
    EndIf
EndProcedure

Procedure ShowIcs()
    Protected lh,h,w,cnt,a$
    lh=19
    h=icscnt*lh:If h>DesktopHeight(0)-#menuhgth:h=DesktopHeight(0)-#menuhgth:EndIf
    w=DesktopWidth(0)-30
    If OpenWindow(#ShowIcsWnd,0,0,w,h,"Raw data",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
        ListViewGadget(#ShowIcsEfid,4,4,w-8,h-8)
        For cnt=1 To icscnt
            a$=Str(cnt)+" >"+DayEvent(cnt)\file+"<"
            AddGadgetItem(#ShowIcsEfid,-1,a$)
        Next
    EndIf
EndProcedure

Procedure ShowDayData()
    Protected lh,h,w,cnt,a$
    lh=19
    h=icscnt*lh:If h>DesktopHeight(0)-#menuhgth:h=DesktopHeight(0)-#menuhgth:EndIf
    w=DesktopWidth(0)-30
    If OpenWindow(#ShowDayWnd,0,0,w,h,"Day data",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
        ListViewGadget(#ShowDayEfid,4,4,w-8,h-8,#PB_ListView_MultiSelect)
        For cnt=1 To icscnt
            a$=Str(cnt)+" "+DayEvent(cnt)\date+"|"+DayEvent(cnt)\time+"|"+DayEvent(cnt)\desc+" ("+DayEvent(cnt)\file+")"
            AddGadgetItem(#ShowDayEfid,-1,a$)
        Next
    EndIf
EndProcedure

Procedure GetIcsData()
    Define cnt,tcnt,txt$
    For cnt=1 To icscnt
        If ReadFile(0,DayEvent(cnt)\file)
            Debug DayEvent(cnt)\file
            While Eof(0)=0
                txt$=ReadString(0)
                ;example = 'DTSTART;TZID=America/Los_Angeles:20160923T103000'
                ;example = 'DTSTART:20160923T103000'
                If Left(txt$,8)="DTSTART:"
                    tcnt+1 : Debug "Found DTSTART:"
                    DayEvent(tcnt)\date=Mid(txt$,9,8)
                    DayEvent(tcnt)\time=Mid(txt$,FindString(txt$,":",1)+10,4)
                EndIf
                If Left(txt$,8)="DTSTART;"
                    tcnt+1 : Debug "Found DTSTART;"
                    DayEvent(tcnt)\date=Mid(txt$,FindString(txt$,":",1)+1,8)
                    DayEvent(tcnt)\time=Mid(txt$,FindString(txt$,":",1)+10,4)
                EndIf
                If Left(txt$,8)="SUMMARY:" : DayEvent(tcnt)\desc=Right(txt$,Len(TXT$)-8) : EndIf
            Wend
            CloseFile(0)               ; close the previously opened file
        Else
            MessageRequester("Information","Couldn't open the file!"+Chr(13)+DayEvent(cnt)\file)
        EndIf
    Next
    icscnt=tcnt
    SortStructuredArray(DayEvent(),#PB_Sort_Ascending,OffsetOf(evntdata\date),TypeOf(evntdata\date),1,icscnt)
EndProcedure

;load data from Calendar folder
Procedure ListFiles(folder$,ext$)
    Define filecnt,fname$
    filecnt=0
    If ExamineDirectory(0,folder$,ext$)
        While NextDirectoryEntry(0)
            Fname$ = DirectoryEntryName(0)
            If DirectoryEntryType(0) = #PB_DirectoryEntry_Directory
                filecnt+1
                CalFolder$(filecnt)=folder$+fname$+"/"
            EndIf
        Wend
    Else
      MessageRequester("Error","Can't examine this directory: "+folder$,0)
    EndIf
    ProcedureReturn filecnt
EndProcedure

Procedure ListEvents(folder$,ext$)
    Define fname$
    If ExamineDirectory(0,folder$,ext$)
        While NextDirectoryEntry(0)
            fname$ = DirectoryEntryName(0)
            If DirectoryEntryType(0) = #PB_DirectoryEntry_File
                icscnt+1
                DayEvent(icscnt)\file=folder$+fname$ 
            EndIf
        Wend
    Else
      MessageRequester("Error","Can't examine this directory: "+folder$,0)
    EndIf
EndProcedure

Procedure LoadEvents()
    Define cnt
    
    ListFiles("/Users/vering2/Library/Calendars/","*.caldav*") ; find caldav folder 
    
    If FindString(CalFolder$(1),"caldav",1)>0
        calcnt=ListFiles(CalFolder$(1),"*.calendar*")
        icscnt=0
        For cnt=1 To calcnt
            listevents(CalFolder$(cnt)+"Events/","*.ics*")
        Next
    EndIf
EndProcedure
;end load data from Calendar folder

Procedure Hskpng()
    Protected w,h,a$
    w=640
    h=400
    If OpenWindow(#HskpngWnd,0,0,w,h,"Housekeeping",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
        SetUpMenus(#HskpngWnd)
        If ExamineDesktops()=0 ; only done once here?
            MessageRequester("ExamineDesktops()","Not found")
        EndIf
        
        If LoadFont(0,"Monaco",10)
            SetGadgetFont(#PB_Default, FontID(0))
        EndIf
        
        ListViewGadget(#HskpngEfid,4,4,w-8,h-8)
        AddGadgetItem(#HskpngEfid,-1,"")
    EndIf
    ;MenuMod()
EndProcedure

Procedure DoMenuEvent(mid)
    Protected filepath$,filename$
    Select mid
    Case #HskpngWnd
        ; don't close windows
    Default
        CloseAllWnds()
    EndSelect
    
    Select mid
        Case #PB_Menu_Quit
            End
        Case #menuload
            LoadEvents()
        Case #menusave
            ;SaveFFile()
        Case #menushowics
            ShowIcs()
        Case #menushowcal
            ShowCalendarFolders()
        Case #menushowday
            ShowDayData()
    EndSelect
EndProcedure

Hskpng()

Define event,wndw

If #PB_Editor_CreateExecutable=0 ; in compile mode so default load
    LoadEvents()
    ;ShowCalendarFolders()
    ;ShowIcs()
    GetIcsData()
    ShowDayData()
EndIf

; loop
Repeat
    event = WaitWindowEvent()
    wndw=EventWindow()
    Select wndw
    Case #HskpngWnd
        Select event
        Case #PB_Event_Menu
            DoMenuEvent(EventMenu())
        Case #PB_Event_CloseWindow
            End
        EndSelect
    Case #ShowCalWnd,#ShowIcsWnd,#ShowDayWnd
        Select event
        Case #PB_Event_CloseWindow
            CloseWindow(wndw)
        EndSelect
    EndSelect
ForEver

Re: Get Calendar events

Posted: Sun Nov 06, 2016 7:31 am
by wilbert
You could also use Cocoa (x64).

Here's some code to get started with that.

Code: Select all

Import "-stdlib=libc++ -mmacosx-version-min=10.7" : EndImport

#EKEntityMaskEvent = 1
#EKEntityMaskReminder = 2

ImportC "-framework EventKit" : EndImport

EventStore = CocoaMessage(0, CocoaMessage(0, 0, "EKEventStore alloc"), 
                          "initWithAccessToEntityTypes:", #EKEntityMaskEvent)

StartInterval.d =     0 ; now
EndInterval.d = 1209600 ; 2 weeks from now
StartDate = CocoaMessage(0, 0, "NSDate dateWithTimeIntervalSinceNow:@", @StartInterval)
EndDate = CocoaMessage(0, 0, "NSDate dateWithTimeIntervalSinceNow:@", @EndInterval)

Predicate = CocoaMessage(0, EventStore, "predicateForEventsWithStartDate:", StartDate,
                         "endDate:", EndDate, "calendars:", #nil)

Events = CocoaMessage(0, EventStore, "eventsMatchingPredicate:", Predicate)

NumEvents = CocoaMessage(0, Events, "count")

i = 0
While i < NumEvents
  Event = CocoaMessage(0, Events, "objectAtIndex:", i) ; EKEvent object
  
  Debug PeekS(CocoaMessage(0, CocoaMessage(0, Event, "description"), "UTF8String"), -1, #PB_UTF8)
  
  i + 1
Wend
You would need to access the EKEvent object properties to get better information.
For this example I simply used 'description'.

Re: Get Calendar events

Posted: Sun Nov 06, 2016 10:21 pm
by WilliamL
Well, my code (edited) works pretty well but it is missing some of the repeating events. I guess some of the dates are calculated so my code misses them. Maybe I can figure out the repeating scheme..

Oh well, it's never simple.

Re: Get Calendar events

Posted: Mon Nov 07, 2016 6:58 am
by wilbert
WilliamL wrote:Well, my code (edited) works pretty well but it is missing some of the repeating events.
Your code doesn't work on my computer. There's no Calenders directory inside the Library directory. :?

Re: Get Calendar events

Posted: Mon Nov 07, 2016 5:42 pm
by WilliamL
There's no Calenders directory inside the Library directory.
Isn't that the way it always works! :? (I can feel Fred's pain)

I worked with the repeating sequences and conquered some of them and soon realized that it is too complicated (too many possibilities) to be worth the effort. If you can't get them all then it is not useable.

I was pleased to be able to get the events in PB but I think that is as far as it will go.

Re: Get Calendar events

Posted: Mon Nov 07, 2016 5:59 pm
by wilbert
WilliamL wrote:Isn't that the way it always works! :?
It's best to check with someone else. Maybe I'm just doing something wrong.
Another possible cause could be that I'm not using the local calendar to store things.
I am using the default calendar app that comes with MacOS but it's connected to my Google account.