[horde] import calendar events into kronolith - using xmlRPC?

Daniel horde at daniu.de
Thu Feb 11 15:14:20 UTC 2016


Zitat von Jan Schneider <jan at horde.org>:

> Zitat von Daniel <horde at daniu.de>:
>
>> Zitat von Daniel <horde at daniu.de>:
>>
>>> Zitat von Michael J Rubinsky <mrubinsk at horde.org>:
>>>
>>>> Quoting Michael J Rubinsky <mrubinsk at horde.org>:
>>>>
>>>>> Quoting Daniel <horde at daniu.de>:
>>>>>
>>>>>> Zitat von Michael J Rubinsky <mrubinsk at horde.org>:
>>>>>>
>>>>>>> Quoting Daniel <horde at daniu.de>:
>>>>>>>
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> Quoting Michael J Rubinsky <mrubinsk at horde.org>:
>>>>>>>>
>>>>>>>>> Quoting Daniel <horde at daniu.de>:
>>>>>>>>>
>>>>>>>>>> Zitat von Michael J Rubinsky <mrubinsk at horde.org>:
>>>>>>>>>>
>>>>>>>>>>> Quoting Michael J Rubinsky <mrubinsk at horde.org>:
>>>>>>>>>>>
>>>>>>>>>>>> Quoting Jan Schneider <jan at horde.org>:
>>>>>>>>>>>>
>>>>>>>>>>>>> Zitat von Daniel <horde at daniu.de>:
>>>>>>>>>>>>>
>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> I am new to the list - hope my request is in the right  
>>>>>>>>>>>>>> place here:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> My final goal is to get a calendar from google into  
>>>>>>>>>>>>>> kronolith. Unfortunately my provider did not setup  
>>>>>>>>>>>>>> kronolith so that I can do that with kronolith itsself  
>>>>>>>>>>>>>> so I think of a cron-job that does that with a php  
>>>>>>>>>>>>>> script (I am not talking about syncing - just copying  
>>>>>>>>>>>>>> the google calendar to kronolith. Since the google  
>>>>>>>>>>>>>> calendar itsself gets populated with a cron-job itsself  
>>>>>>>>>>>>>> it's ok to have accurate data only after copying). I  
>>>>>>>>>>>>>> can already read all appointments from google (caldav  
>>>>>>>>>>>>>> still works) - so I got a string with Vevent infos. The  
>>>>>>>>>>>>>> plan is to purge the existing calendar in kronolith and  
>>>>>>>>>>>>>> write all events from the string into the existing  
>>>>>>>>>>>>>> calendar.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> I tried to adjust this: http://theupstairsroom.com/66  
>>>>>>>>>>>>>> but don't seem to get it working at all. Partly because  
>>>>>>>>>>>>>> I don't have access to horde sources on the server from  
>>>>>>>>>>>>>> which I connect to the Horde - so I need to use another  
>>>>>>>>>>>>>> RPC-client. I would like to use the RPC-client built in  
>>>>>>>>>>>>>> php (epinion.com) which is turned on according to  
>>>>>>>>>>>>>> phpinfo. Somehow I cannot really find a good tutorial  
>>>>>>>>>>>>>> how to do that.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Adjusting a script from php.net gave me the attached  
>>>>>>>>>>>>>> attempt. That one does nothing unfortunately ... (but  
>>>>>>>>>>>>>> at least no error message)
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Can someone point me in the right direction? Or is  
>>>>>>>>>>>>>> there a simpler way to achieve what I want to do?
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Is https a problem for what I want to do? Are my  
>>>>>>>>>>>>>> adjustments for that correct?
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Looking at the api it seems like the purge function  
>>>>>>>>>>>>>> from import in the GUI did not make it in there ... any  
>>>>>>>>>>>>>> chance to still do it or get it in the api?
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Thanks for any input!
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> (BTW: there is a sourceforge project with exactly that  
>>>>>>>>>>>>>> topic, but it does not work any more and the author did  
>>>>>>>>>>>>>> not maintain it - I even asked him and he says he  
>>>>>>>>>>>>>> cannot help -  
>>>>>>>>>>>>>> http://sourceforge.net/projects/kron2gcalsync/)
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> ***
>>>>>>>>>>>>>> function do_call($host, $port, $request) {
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> $url = "https://$host:$port/";
>>>>>>>>>>>>>> //echo $url;
>>>>>>>>>>>>>> $header[] = "Content-type: text/xml";
>>>>>>>>>>>>>> $header[] = "Content-length: ".strlen($request);
>>>>>>>>>>>>>> $to['user']='username';
>>>>>>>>>>>>>> $to['pass']='password';
>>>>>>>>>>>>>> $userpwd = $to['user'] .":". $to['pass'];
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> $ch = curl_init();
>>>>>>>>>>>>>> curl_setopt($ch, CURLOPT_URL, $url);
>>>>>>>>>>>>>> curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
>>>>>>>>>>>>>> curl_setopt($ch, CURLOPT_TIMEOUT, 1);
>>>>>>>>>>>>>> curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
>>>>>>>>>>>>>> curl_setopt($ch, CURLOPT_USERPWD, $userpwd);
>>>>>>>>>>>>>> curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
>>>>>>>>>>>>>> curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
>>>>>>>>>>>>>> curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> $data = curl_exec($ch);
>>>>>>>>>>>>>> if (curl_errno($ch)) {
>>>>>>>>>>>>>> print curl_error($ch);
>>>>>>>>>>>>>> } else {
>>>>>>>>>>>>>> curl_close($ch);
>>>>>>>>>>>>>> return $data;
>>>>>>>>>>>>>> }
>>>>>>>>>>>>>> }
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> $host="path/rpc.php";
>>>>>>>>>>>>>> $port=443;
>>>>>>>>>>>>>> $request =  
>>>>>>>>>>>>>> xmlrpc_encode_request('kronolith.listCalendars',  
>>>>>>>>>>>>>> array());
>>>>>>>>>>>>>> $response = do_call($host, $port, $request);
>>>>>>>>>>>>>> echo $response;
>>>>>>>>>>>>>> ***
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> regards
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> -- 
>>>>>>>>>>>>>> Horde mailing list
>>>>>>>>>>>>>> Frequently Asked Questions: http://horde.org/faq/
>>>>>>>>>>>>>> To unsubscribe, mail: horde-unsubscribe at lists.horde.org
>>>>>>>>>>>>>
>>>>>>>>>>>>> You want to use the kronolith-import-icals script that  
>>>>>>>>>>>>> comes with Kronolith.
>>>>>>>>>>>>
>>>>>>>>>>>> This is correct, if you have shell access. If you don't,  
>>>>>>>>>>>> you should probably change to JSON as Jan suggests below.  
>>>>>>>>>>>> In newer versions of Horde we no longer support xmlrpc.
>>>>>>>>>>>>
>>>>>>>>>>>> Also:
>>>>>>>>>>>> 1) Don't set the port number in CURL when you use  
>>>>>>>>>>>> https:// already in the URL.
>>>>>>>>>>>> 2) The proper method name would be  
>>>>>>>>>>>> "calendar.listCalendars", not "kronolith.listCalendars".
>>>>>>>>>>>>
>>>>>>>>>>>> So, for example (this is VERY rough and quickly done, so  
>>>>>>>>>>>> you might need to tweak some things):
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> function do_call($host, $method, $params) {
>>>>>>>>>>>> $url = "https://$host";
>>>>>>>>>>>> $header[] = "Content-type: application/json";
>>>>>>>>>>>> $data = array('version' => '1.1', 'method' => $request);
>>>>>>>>>>>
>>>>>>>>>>> Sorry, this line should be (substitute $method for $request):
>>>>>>>>>>> $data = array('version' => '1.1', 'method' => $method);
>>>>>>>>>>
>>>>>>>>>> sure - I found that ... works great! THANKS a lot!
>>>>>>>>>>
>>>>>>>>>> So now how about the other things:
>>>>>>>>>> *do I need to delete all events manually or may I beg for a  
>>>>>>>>>> purge to be implemented in the api?
>>>>>>>>>
>>>>>>>>> Use the calendar.deleteCalendar method.
>>>>>>>>
>>>>>>>> I guess that should delete the calendar, not purge it?  
>>>>>>>> However I can't get that one to work ...
>>>>>>>
>>>>>>> Correct, which is the same thing that happens when you select  
>>>>>>> the purge checkbox in the UI.
>>>>>>
>>>>>> I don't think so ... that would mean that the calendar would  
>>>>>> get a new id after doing this or is it possible to define the  
>>>>>> id somehow? Are we talking about the same thing? I am talking  
>>>>>> about importing data (ical) in the ui and ticking "delete all  
>>>>>> data in the calendar" (sorry, my ui is german)
>>>>>
>>>>> It looks like our PHP doc is incorrect.  
>>>>> Kronolith_Driver::delete() is *supposed* to
>>>>> "Delete a calendar and all of it's events", but looking at the  
>>>>> actual source code,
>>>>> it only removes the events.
>>>>>
>>>>> In anticipation of your next question, the reason the events are  
>>>>> all removed individually (and not all at once as would be much  
>>>>> more efficient especially in a SQL backend) is because we need  
>>>>> to track the deletions in the Horde_History system for  
>>>>> synchronization clients.
>>>>>
>>>>>>>> ***
>>>>>>>> $request = 'calendar.deleteCalendar';
>>>>>>>>
>>>>>>>> $params = array('calendar-id');
>>>>>>>>
>>>>>>>> $response = do_call($host, $request, $params);
>>>>>>>> echo $response;
>>>>>>>> ***
>>>>>>>>
>>>>>>>> gives me:
>>>>>>>> {"version":"1.1","error":{"name":"JSONRPCError","code":999,"message":{"details":null,"logged":false}}}
>>>>>>>
>>>>>>> This looks like it should work (assuming it's the correct  
>>>>>>> calendar id and you have enough rights to remove it). Without  
>>>>>>> details from the server's log it's hard to say why it's not.
>>>>>>>
>>>>>>>>>> *Can I import the events with the api yet?
>>>>>>>>>>
>>>>>>>>>> I tried that one - (function and host omitted)
>>>>>>>>>>
>>>>>>>>>> ***
>>>>>>>>>> $request = 'calendar.import';
>>>>>>>>>> $input = <<<EOF
>>>>>>>>>> BEGIN:VEVENT
>>>>>>>>>> UID:20160901T130000Z-123401 at host.com
>>>>>>>>>> DTSTAMP:20160110T1300Z
>>>>>>>>>> DTSTART:20160110T163000Z
>>>>>>>>>> DTEND:20160110T190000Z
>>>>>>>>>> SUMMARY:Test1
>>>>>>>>>> END:VEVENT
>>>>>>>>>> UID:20160902T130000Z-123401 at host.com
>>>>>>>>>> DTSTAMP:20160111T1300Z
>>>>>>>>>> DTSTART:20160111T163000Z
>>>>>>>>>> DTEND:20160111T190000Z
>>>>>>>>>> SUMMARY:Test2
>>>>>>>>>> END:VEVENT
>>>>>>>>>> EOF;
>>>>>>>>>> $params = array($input,'text/calendar','calendar-id');
>>>>>>>>>> $response = do_call($host, $request, $params);
>>>>>>>>>> echo $response;
>>>>>>>>>> ***
>>>>>>>>>>
>>>>>>>>>> which imported just the first event ... any chance to make  
>>>>>>>>>> it import many events with one call? I am afraid that I get  
>>>>>>>>>> a timeout for the script otherwise ...
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Correct, you can only import one VEVENT at a time.
>>>>>>>>>
>>>>>>>>> I'm confused by your statement about a timeout. A single  
>>>>>>>>> event will import faster than a large calendar. You are  
>>>>>>>>> likely to get server timeouts importing the full calendar at  
>>>>>>>>> once.
>>>>>>>>>
>>>>>>>>>> I'd love to see a function like this:
>>>>>>>>>> public function import_many($content, $contentType,  
>>>>>>>>>> $calendar = null, $purge = FALSE)
>>>>>>>>>>
>>>>>>>>>> while it won't help me since my provider would not update  
>>>>>>>>>> Horde just for me ...
>>>>>>>>
>>>>>>>> just for reference:
>>>>>>>> I was wrong - just as my string was - there was 1  
>>>>>>>> BEGIN:VEVENT missing. Adding that missing part, I can import  
>>>>>>>> many events at once.
>>>>>>>
>>>>>>> Ah. Great. Not sure why I thought that :)
>>>>>>>
>>>>>>>
>>>>>>>> concerning timeout: I was refering to timeout of my php  
>>>>>>>> script, not the connection to the server within the php  
>>>>>>>> script. I guess it is faster if I send all events as 1 string  
>>>>>>>> than sending each event with a seperate call.
>>>>>>>
>>>>>>> True. Though it takes longer on the server to process it.  
>>>>>>> Probably not an issue, but keep that in mind (your host may  
>>>>>>> have a too-low timeout configured on the server).
>>>>>>>
>>>>>>>> I guess I'm going to see how long it takes and in case of a  
>>>>>>>> problem break the string in parts. Since I don't need the ids  
>>>>>>>> afterwards should be OK like that.
>>>>>>
>>>>>> changed the code slightly for better handling (don't need to  
>>>>>> remove any username, host or password). Now I got 2 functions:
>>>>>>
>>>>>> the first one does work, but gets timed out so that I gotta  
>>>>>> call it at least once more so that the calendar is empty (php  
>>>>>> timeout is 60sec I think and it's around 700 events). The  
>>>>>> second does nothing ...
>>>>>>
>>>>>> Would appreciate if someone could test, especially what  
>>>>>> delete_cal does - remove the calendar or delete all events in it.
>>>>>
>>>>> Ok. The calendar/deleteCalendar method does just that, it *only*  
>>>>> removes the actual calendar share - it doesn't touch the events  
>>>>> storage.
>>>>
>>>> *sigh* Sorry - this is incorrect. calendar/deleteCalendar does  
>>>> both. It removes
>>>> the events (by calling Kronolith_Driver::delete()) and then it  
>>>> removes the calendar
>>>> share itself. So, you only have to call that one method, you  
>>>> don't have to iterate over the events on your own.
>>>>
>>>> Sorry for the confusion.
>>>
>>> Hi
>>>
>>> do I get it right, that after calling deleteCalendar the calendar  
>>> should be gone?
>>>
>>> On the server I am talking to it does nothing.
>>>
>>> Basically my problem however is that I do not yet know how to  
>>> really read from a caldav (in this case google) server what has  
>>> changed lately. I wanted to spare myself that and just erase  
>>> everything and write it once more (I had found a php script that  
>>> does that for owncloud which is really fast because there is a  
>>> command to erase all events at once in owncloud).
>>>
>>> I tweaked the code now so that it does only write events that had  
>>> been changed today (could adjust that to "lately") but that does  
>>> not erase events from kronolith that had been deleted on google.
>>>
>>> well - seems like the remaining problem does not belong here any  
>>> more and I gotta learn howto talk caldav ...
>>
>> Hi.
>>
>> sorry - now I got some problem again:
>>
>> I wrote this delete uid function:
>>
>>
>> function delete_id($host, $user, $pw, $id) {
>>
>>      $url = "https://$host";
>>      $header[] = "Content-type: application/json";
>>      $input = array('version' => '1.1', 'method' =>  
>> 'calendar.delete', 'params' => $id);
>>      $userpwd = $user . ':' . $pw;
>>      $ch = curl_init();
>>      curl_setopt($ch, CURLOPT_URL, $url);
>>      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
>>      curl_setopt($ch, CURLOPT_TIMEOUT, 1);
>>      curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
>>      curl_setopt($ch, CURLOPT_USERPWD, $userpwd);
>>      curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
>>      curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
>>      curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($input));
>>      $data = curl_exec($ch);
>>      $processed=json_decode($data, true);
>>      if (curl_errno($ch)) {
>>          print curl_error($ch);
>>      } else {
>>          curl_close($ch);
>>          return $data;
>>      }
>> }
>>
>> But unfortunately I get this reply (var_dump or $data):
>>
>> {"version":"1.1","error":{"name":"JSONRPCError","code":999,"message":"Parameters must be JSON objects or  
>> arrays."}}
>
> Because your parameters are not an array or object:
> 'params' => $id

Hi,

thanks for the reply - I had tried to change it to:
       $input = array('version' => '1.1', 'method' =>  
'calendar.delete', 'params' => array($id));

which does not work either ...

{"version":"1.1","error":{"name":"JSONRPCError","code":999,"message":{"details":null,"logged":false}}}

any more ideas? I wonder that I am not asked for a calendar id ... Or  
is the uid independant of calendar id?

regards



More information about the horde mailing list