Get Calendar events

Mac OSX specific forum
WilliamL
Addict
Addict
Posts: 1224
Joined: Mon Aug 04, 2008 10:56 pm
Location: Seattle, USA

Get Calendar events

Post 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
Last edited by WilliamL on Sun Nov 06, 2016 10:15 pm, edited 2 times in total.
MacBook Pro-M1 (2021), Sonoma 14.4.1, PB 6.10LTS M1
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Get Calendar events

Post 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'.
Windows (x64)
Raspberry Pi OS (Arm64)
WilliamL
Addict
Addict
Posts: 1224
Joined: Mon Aug 04, 2008 10:56 pm
Location: Seattle, USA

Re: Get Calendar events

Post 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.
MacBook Pro-M1 (2021), Sonoma 14.4.1, PB 6.10LTS M1
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Get Calendar events

Post 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. :?
Windows (x64)
Raspberry Pi OS (Arm64)
WilliamL
Addict
Addict
Posts: 1224
Joined: Mon Aug 04, 2008 10:56 pm
Location: Seattle, USA

Re: Get Calendar events

Post 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.
MacBook Pro-M1 (2021), Sonoma 14.4.1, PB 6.10LTS M1
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Get Calendar events

Post 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.
Windows (x64)
Raspberry Pi OS (Arm64)
Post Reply