Sun Calendar Sync for Apple iCal

Building off the work by John Littell and Jason Carolan, I am releasing here icalds 2.0 that enables you to subscribe to a Sun Calendar Server from an Apple iCal client on Mac OS X, and subsequently sync with "any" mobile device thru iSync. I am myself using it on Mac OS X 10.5.5 with Sun Calendar Server 6.3. icalds will prove useful until Sun Calendar Server adds native CalDAV support.

Compared to the previous releases of the icald/icalds scripts, fixes include:

  • session id now recognizes non-alphabetic characters (presence of % character)
  • http post request now conforms to what Sun Cal expects (6.3 responded Unauthorized to export.wcap)
  • now using http post request at login for increased security (password no longer visible in web server log)
  • strip out html tags generated by Namefinder for better readability
  • suid no longer required by default values for log/pid file location
  • organizer field is now kept and passed on to iCal

You would want to use icalds if you maintain your calendar online on a Sun Calendar Server --like we do at Sun Microsystems-- but want to have a copy on your Mac and/or sync it to a non-3G mobile device --you can directly sync a 3G device to Sun Calendar Server through SyncML. I myself sync it with a Nokia cellphone and an old Palm PDA. icalds runs as a daemon on your Mac so you do not need to explicitely run it, iCal will simply sync at the frequency you tell it to. You could also use icalds to maintain your calendar on a Mac and publish it to a Sun Calendar Server but I haven't tried/debugged that use-case so you may run into issues; let we know if you do.

To get going with icalds, download the icalds.pl Perl script then follow these steps:

  1. Create directories, copy files
    • create a bin folder in home folder (if not already there)
    • copy icalds.pl and icalds.command into bin/
    • make both scripts executable (chmod a+x icalds\*)
  2. Update Perl
    • login as root if you've enabled that, use sudo otherwise
    • start CPAN (perl -MCPAN -e shell)
    • install all modules listed in icalds.pl
    • if missing, download SSL module
  3. Edit files
    • edit UserName, CalendarServer, PortNumber in icalds.command
    • optionally, edit paths in for PIDFILE and LOGFILE icalds.pl
    • in the unlikely event your calendar server is accessible via http and not https, change the 4 occurences of https to http in icalds.pl
  4. Make run on login
    • add icalds.command execute on login in Preferences>Accounts>Login Items
    • logout and log back in, or just run icalds.command at the command line
  5. Subscribe in iCal
    • suscribe to http://locahost:7081/login/<username>
    • use username and password
    • you can subscribe to sub-calendars using http://locahost:7081/login/<username>/<calname>

If you are a heavy user of recurring events and multiple timezones, you will see that iCal does not display properly these events. I believe I know how to fix icalds for it to work --change DTSTART time from a UTC time to a local time-- but I haven't had the time to do it. Events are displayed fine in my Nokia and my Palm though so the buggy display is not transmitted thru iSync.

Comments:

I have submitted BugID 6430273 to Apple on this. Synopsis is : iCal does not deal with UTC times in DTSTART and DTEND when importing ICS file.

Posted by Frederic Pariente on December 09, 2008 at 07:39 AM CET #

I can get connected and see my calendar entries but it seems that it displays repeating events that I've deleted in the past. I have a debug file if you'd like to see it.

Posted by Anthony on December 09, 2008 at 03:18 PM CET #

After digging a little more I've found that my problem does not involve your script. It was a export/import problem. Thanks for the script!

Posted by Anthony Mayes on December 09, 2008 at 04:00 PM CET #

Anthony, I'm glad icalds is proving useful. You may still see some errors with recurring events. DST seems not to be taken into account when DTSTART and DTEND times are specified in Zulu timezone, as it is the case for my work Calendar Server. iCal accepts Zulu times in other fields though (e.g. RRULE, EXCLUDE). I submitted BugID 6430273 on this but do not expect any quick fix from Apple. I also googled for some Perl code to convert ICS dates between timezones with no success. My last resort will be to write my own subroutine, when I can dedicate more time to icalds.

Posted by Frederic Pariente on December 10, 2008 at 01:32 AM CET #

i get an error:

error subscribing to the calendar
code 30

any idea?

thank you

Posted by chrid on February 14, 2009 at 03:49 PM CET #

There is a debug mode that you can turn on (launch script with -d or edit Perl script to set $DEBUG=1). It creates an add'l log file where you see the exchange with the Calendar Server. Can you try it? What does it say?

Posted by Frederic Pariente on February 15, 2009 at 03:36 PM CET #

in the logfile it says:
Use of uninitialized value in string ne at /users/chrid/bin/icalds.pl line 314.
192.168.1.103 - - [15/Feb/2009:23:54:53 +0100] "GET /login/chrid" 401 539
Can't call method "code" on an undefined value at /users/chrid/bin/icalds.pl line 211.

sorry i am not a perl user at all
thx for any help!

Posted by chrid on February 15, 2009 at 04:00 PM CET #

hi frederic,

i fixed this one. i put the url in the command file with https and / etc. without that it now connects but says it:
No calendar was found on http://localh...... . Please check the URL.
And a lot of stuff in the debug file, requests to the calendar. This are for sections
1. Request: https://www.xxx.xxx:xx/get_calprops.wcap with the X-NSCP-WCAP-ERRNO:29
2. Request: https://www.xxx.xxx:xx/login.wcap with the X-NSCP-WCAP-ERRNO:0
3. Request: https://www.xxx.xxx:xx/get_calprops.wcap with the X-NSCP-WCAP-ERRNO:29
4. Request: https://www.xxx.xxx:xx/logout.wcap
with the X-NSCP-WCAP-ERRNO:-1

In the log it says
se of uninitialized value in string ne at ..../bin/icalds.pl line 314.
Useless content call in void context at ..../bin/icalds.pl line 521

thx for any help
christian

Posted by chrid on February 15, 2009 at 04:41 PM CET #

From the Sun Calendar documentation on docs.sun.com, error 29 is CALENDAR_DOES_NOT_EXIST (see http://docs.sun.com/source/816-6416-10/pr10WCAP.html#53182). It could be a typo in your calname. It could also be that it does not exist yet. Can you connect to the Calendar Server through the Calendar Express web interface? Should simply be https://www.xxx.xxx/ in your case. The calendar will be created at login in case it did not exist before. If you simply cannot login through Calendar Express, there is no way the Perl script will work either. Check with your sysadmin then what is your username for the Calendar Server, it could be different from your Unix login.

As for the warning (uninitialized variable, void content), that's normal.

Hope this helps.

Posted by Frederic Pariente on February 16, 2009 at 07:01 AM CET #

Hi,

the calendar works fine in the webclient and also in thunderbird lightning.

Posted by chrid on February 16, 2009 at 07:30 AM CET #

Hi Frederic,

i could just solve the problem. as url i had to put in the full user name including @domain. no it works fine.

THANK YOU VERY MUCH FOR THIS TOOL! I NOW CAN SYNC TO MY IPHONE without using a google calendar account etc....

best regards from vienna,

christian

Posted by chrid on February 16, 2009 at 09:15 AM CET #

Dear Frederic,
thank you for this script!

Unfortunately, I cannot make it work just yet.

I downloaded your script and it runs fine. I can subscribe to my calendar (which I could not until I got the port straight), but now, I do not see any calendar contents, and I get an unexpected error when updating the calendar, error 4 (this is my translation from German).

I turned debug on, and I receive this message in the error log:

127.0.0.1 - - [20/Feb/2009:10:58:40 +0100] "GET /login/Anke" 401 539
127.0.0.1 - Anke [20/Feb/2009:10:58:40 +0100] "GET /login/Anke" 200 431852

and this one in the terminal, where the scrip runs:
Use of uninitialized value in string ne at /Users/hildebra/bin/icalds.pl line 314.
Useless content call in void context at /Users/hildebra/bin/icalds.pl line 521

sorry, I am a perl novice.
Thank you for any hints.
Anke

Posted by anke on February 20, 2009 at 03:05 AM CET #

Could it be that you have sub-calendars? If so, from iCal, subscribe to .../Anke/calname.

As for the debug log, you need to look in the other file /var/tmp/icalds.debug. What do you see there?

Posted by Frederic Pariente on February 20, 2009 at 03:40 AM CET #

Hi,

Wow. The icalds.debug file shows my calendar and to do list. It is pretty long .. Can you point me to a particular place I should check?

I have only one calendar, but I am subscribed to others, which I tihnk would not qualify as sub-calendar .. ?

Posted by Anke on February 20, 2009 at 04:09 AM CET #

If you see your calendar, that's a good start, the connection to the server works. Some ideas...

1. Look at the WCAP commands and check that X-NSCP-WCAP-ERRNO is 0 (means ok).

2. Cut-n-paste your calendar data (from BEGIN:VCALENDAR to END:VCALENDAR) into a file called test.ics and try to open it with iCal.

3. Try deleting some calendars in iCal and restarting it. iCal has been unstable at times for me.

4. Try subscribing to your calendar without ToDo's or alarms. I have not tested these myself, maybe there's a bug in icalds with these.

That's all I can think of right now... time for lunch :)

Posted by Frederic Pariente on February 20, 2009 at 04:19 AM CET #

SUCCESS!!!

Thank you, I got it.

The problem was with one particular event. This had been an invitation to the entire Company, and had apparently been to the emaillist subscribers of mycompany_all@mycompany.de . iCal liked all my other invitations except this particular one. I figured it out be sequentially removing events from the calendar, and importing the file per hand as you said, until it worked.

Fix: I removed this particular event from my work calendar and the everything works fine now.

Thank you very much for this Tool and your help with making it work!

Posted by Anke on February 20, 2009 at 06:42 AM CET #

I'm glad you got it to work, Anke. Could you post here the "bad" calendar entry? So I could try to debug & update icalds to make it work with it. Make sure to anonymize the data first, of course. Thanks!

Posted by Frederic Pariente on February 20, 2009 at 06:46 AM CET #

Hi Frederic,
here is the event that caused problems, cut from the debug file.
Again, thanks for the help and getting this to run!
anke

BEGIN:VEVENT
UID:00000000000000000000000000000000d9da7d497e7c0000d8020000e5030000
DTSTAMP:20090220T125605Z
SUMMARY:IT Infoveranstaltung 11.02.2009
DTSTART:20090211T090000Z
DTEND:20090211T100000Z
CREATED:20090126T154704Z
LAST-MODIFIED:20090211T115307Z
PRIORITY:0
SEQUENCE:0
DESCRIPTION:\\r\\nLots of invitation text which I erased (anke)\\r\\n
CLASS:PUBLIC
ORGANIZER;CN="Max Organizer"
;X-S1CS-EMAIL=max.organizer@mycompany.de
:orginizerloginname
STATUS:CONFIRMED
TRANSP:OPAQUE
ATTENDEE;ROLE=REQ-PARTICIPANT;CUTYPE=INDIVIDUAL
;PARTSTAT=NEEDS-ACTION;CN="Max FirstInvitee"
;MEMBER="mycompany_all@mycompany.de"
;RSVP=TRUE
;X-NSCP-ATTENDEE-GSE-STATUS=2
;X-S1CS-EMAIL=max.firstinvitee@myconpany.de
:firstinviteeloginname
ATTENDEE;ROLE=REQ-PARTICIPANT;CUTYPE=INDIVIDUAL
;PARTSTAT=NEEDS-ACTION;CN="Max SecondInvitee"
;MEMBER="mycompany_all@mycompany.de"
;RSVP=TRUE
;X-NSCP-ATTENDEE-GSE-STATUS=2
;X-S1CS-EMAIL=max.firstinvitee@myconpany.de
:secondinviteeloginname

many more invitees here, I have 10000 lines of this
after the last invitee the end is:

X-NSCP-ORIGINAL-DTSTART:20090211T090000Z
X-NSCP-LANGUAGE:de
X-NSCP-TOMBSTONE:0
X-NSCP-ONGOING:0
X-NSCP-ORGANIZER-EMAIL:max.organizer@mycompany.de
X-NSCP-GSE-COMPONENT-STATE;X-NSCP-GSE-COMMENT="REPLY-ACCEPTED":262176
END:VEVENT

Posted by Anke on February 21, 2009 at 07:13 AM CET #

I think I have traced back the issue to the MEMBER param that iCal does not seem to like. I have a modified version of icalds for you to test at http://opensolaris.free.fr/icalds/icalds.pl . Can you verify the fix? If it works, I'll post a quick blog to "officially" release this new version :) Thanks again!

Posted by Frederic Pariente on February 27, 2009 at 02:04 AM CET #

Hi all,

i wrote a function in PHP to export a calendar for Mac iCal some days ago; recently, i have patched the scripts to get rid of the ";MEMBER" lines. If anyone has interest, please contact me!

Best,
- Wulf

Posted by Wulf Kaiser on April 01, 2009 at 08:19 AM CEST #

When you say this ...

"You could also use icalds to maintain your calendar on a Mac and publish it to a Sun Calendar Server but I haven't tried/debugged that use-case so you may run into issues; let we know if you do."

... you mean you haven't even tested it ever once? When I try to publish a given calendar to one specifically created on the server for that purpose (called "work") I always get a message that /login/<username>/work/Work.ics was not found on the server. Or am I doing smth. blatantly wrong?

Also, the the pull variant does not synch todos, does it?

TIA,
Karl.

Posted by Karl H. Beckers on April 07, 2009 at 05:27 PM CEST #

Yes, that's what I meant, I haven't tested it, nor (much) changed the PUT part of the script from its original version, in fact. Now that there is a user though (you), I'll give it a try. Ditto for TODO's.

Will post back soon with my findings...

Posted by Frederic Pariente on April 08, 2009 at 02:30 AM CEST #

So I tried... it seems the script is passing work.ics instead of username:work as it should... Sun Calendar Server logically returns with an error 29 CALENDAR_DOES_NOT_EXIST... should not be too hard to fix. To be cont'd.

Posted by Frederic Pariente on April 08, 2009 at 09:05 AM CEST #

Error 29 is in fact the result of not properly inputing the URL string in the Publish window. If you have created a sub-calendar "work" on the Sun server, you should use in iCal "Publish Calendar as: work" and "Base URL : http://localhost:7081/username/" for the "private server". Along with login and password info.

I am myself however getting an error 35 next; nothing is eventually written on the Sun side. I may need to strip out some of the iCal extensions in the data sent back to the Sun server. Unless it's because I was publishing a calendar with date-to-date events..?

Karl, are you getting past error 29 now? Are you seeing your data on the Sun side?

Posted by Frederic Pariente on April 08, 2009 at 10:27 AM CEST #

Here is the mentioned PHP script for exporting a calendar for Mac iCal:

<code>
#!/usr/local/bin/php -q

<?php

setlocale(LC_ALL, 'de_DE.UTF8');

require('dateTime.php');

function URLopen($url) {

ini_set('user_agent','MSIE 4\\.0b2;');

$dh = fopen("$url",'r');
$result = fread($dh,8192);

return $result;}

$start = mktime(0, 0, 0, date("m")-2, date("d"), date("Y"));
$startExport = date("Y-m-d", $start);

$startJahr = substr($startExport, 0, 4);
$startMonat = substr($startExport, 5, 2);

$startTag = substr($startExport, 8, 2);
$startZeit = "08:00";

function gmt2utc($day,$month,$year,$time) {

$isSummertime = date("I", mktime(0,0,0,$month,$day,$year));

$Hour = substr($time, 0, 2);

switch ($isSummertime) {

case '0': $HourUTCin = $Hour - 1; break;
case '1': $HourUTCin = $Hour - 2; break;}

if (($HourUTCin >= '1') && ($HourUTCin <= '9')) {

$HourUTCout = "0$HourUTCin";}

else {

$HourUTCout = $HourUTCin;}

return $HourUTCout;}

$u_startDate = "$startJahr" . "$startMonat" . "$startTag";
$u_startHour = gmt2utc($startTag,$startMonat,$startJahr,$startZeit);
$u_startMinute = substr($startZeit, 3);
$u_startDate = $u_startDate . "T" . "$u_startHour" . "$u_startMinute" . "00" . "Z";

$end = mktime(0, 0, 0, date("m")+3, date("d"), date("Y"));
$endExport = date("Y-m-d", $end);

$endJahr = substr($endExport, 0, 4);
$endMonat = substr($endExport, 5, 2);
$endTag = substr($endExport, 8, 2);
$endZeit = "08:00";

$u_endDate = "$endJahr" . "$endMonat" . "$endTag";
$u_endHour = gmt2utc($endTag,$endMonat,$endJahr,$endZeit);
$u_endMinute = substr($endZeit, 3);
$u_endDate = $u_endDate . "T" . "$u_endHour" . "$u_endMinute" . "00" . "Z";

$curl = curl_init();

if (!$curl) {

die("Unable to create a cURL Session");}

$wcapConnect = curl_setopt($curl, CURLOPT_URL,"https://yourcalendar.com/login.wcap?refresh=1&user=wcapuser&password=wcappass");
$wcapConnect = curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
$wcapConnect = curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$wcapConnect = curl_exec($curl);

$count1 = strpos($wcapConnect, "X-NSCP-WCAP-SESSION-ID:");
$count1 = $count1 + 23;
$count2 = strpos($wcapConnect, "X-NSCP-WCAP-USER-ID:");
$diff = $count2 - $count1;
$calSessID = substr($wcapConnect, $count1, $diff);
$calSessID = trim($calSessID);

global $calSessID;

$curlExport = curl_init();

$export = curl_setopt($curlExport, CURLOPT_URL,"https://yourcalendar.com/export.wcap");
$export = curl_setopt($curlExport, CURLOPT_POSTFIELDS, "calid=calendar2export&dtstart=$u_startDate&dtend=$u_endDate&content-out=text/calendar");
$export = curl_setopt($curlExport, CURLOPT_SSLVERSION, 3);
$export = curl_setopt($curlExport, CURLOPT_SSL_VERIFYPEER, 0);
$export = curl_setopt($curlExport, CURLOPT_POST, 1);
$export = curl_setopt($curlExport, CURLOPT_HEADER, 0);
$export = curl_setopt($curlExport, CURLOPT_RETURNTRANSFER, 1);
$export = curl_exec($curlExport);

unlink("/tmp/calendar2export.ics");

$export = trim($export);
global $export;

$file = fopen("/tmp/calendar2export.ics", "w+");
$text = $export;
fwrite($file, $text);
fclose($file);

chmod("/tmp/calendar2export.ics", 0777);

curl_close($curlExport);
curl_close($curl);

sleep(3);

$replace4Mac = ";MEMBER";

$original = file("/tmp/calendar2export.ics");
$output = fopen("/tmp/calendar2export.ics", "w");

foreach($original as $zeile) {

if(!preg_match("/".$replace4Mac."/i", $zeile)) {

fputs($output, $zeile);}}

?>
</code>

It runs as cron on the command line.

Posted by Wulf Kaiser on April 09, 2009 at 03:00 AM CEST #

Well,
I can finish the publish calendar dialog.
Only, if I add an event locally, nothing gets written. I'm also getting error 35 ... dunno if the 401 first is related, can't quit correlate icald.debug and icald.log. Here's what I get in the log:

127.0.0.1 - - [11/Apr/2009:22:18:31 +0200] "PUT " 401 495
Useless content call in void context at /Users/name/bin/icalds.pl line 609
Useless content call in void context at /Users/name/bin/icalds.pl line 532
127.0.0.1 - name [11/Apr/2009:22:18:34 +0200] "PUT /name/work.ics" 200 26
Use of uninitialized value in string ne at /Users/name/bin/icalds.pl line 229.
Use of uninitialized value in concatenation (.) or string at /Users/name/bin/icalds.pl line 294.
127.0.0.1 - - [11/Apr/2009:22:19:07 +0200] "PUT " 401 495
Useless content call in void context at /Users/name/bin/icalds.pl line 609
Useless content call in void context at /Users/name/bin/icalds.pl line 532
127.0.0.1 - name [11/Apr/2009:22:19:09 +0200] "PUT /name/work.ics" 200 26

Also, what I'd really want to do is sync to the main calendar, eventually. But maybe that's smth. for later.

Thanks,
Karl.

Posted by Karl H. Beckers on April 11, 2009 at 03:38 PM CEST #

Karl, just a quick note to let you know I have a fix. I need a few days to get to it then will post it to the main blog. Tschuss.

Posted by Frederic Pariente on April 15, 2009 at 02:41 AM CEST #

Cool ... looking forward to that. Thanks!

Posted by Karl H. Beckers on April 15, 2009 at 03:22 AM CEST #

Hi all.

I'm trying to install this tool, and I get this error using the debug mode, when I try tu subscribe to the SUN Calendar:

$ ./icalds.command
Use of uninitialized value in string ne at /Users/mgil/bin/icalds.pl line 326.
Can't call method "code" on an undefined value at /Users/mgil/bin/icalds.pl line 211.

I can use Lighting extension under thunderbird without problems, I can login to the SUN Calendar too without problems.

Thanks.

Posted by Manuel on June 29, 2009 at 04:19 AM CEST #

The first error/warning message ("use of uninitialized value") is harmless, I think. The second seems to tell that you did not get a proper HTTP::Response initialized. Is your Perl environment ok? Are you writing your log in a writeable location? Can you show which line you use for subscribing? the debug log?
Thanks.

Posted by Frederic Pariente on June 29, 2009 at 05:13 AM CEST #

hi frederic,

as i updatet to osx10.6 icalds does not work anymore any idea what could have happend i am not a perl guy at all sorry.
here is the error message
Can't locate Crypt/SSLeay.pm in @INC (@INC contains: /Library/Perl/Updates/5.10.0 /System/Library/Perl/5.10.0/darwin-thread-multi-2level /System/Library/Perl/5.10.0 /Library/Perl/5.10.0/darwin-thread-multi-2level /Library/Perl/5.10.0 /Network/Library/Perl/5.10.0/darwin-thread-multi-2level /Network/Library/Perl/5.10.0 /Network/Library/Perl /System/Library/Perl/Extras/5.10.0/darwin-thread-multi-2level /System/Library/Perl/Extras/5.10.0 .) at /users/chrid/bin/icalds.pl line 24.
BEGIN failed--compilation aborted at /users/chrid/bin/icalds.pl line 24.

thx a lot

christian

Posted by chrid on September 09, 2009 at 12:35 PM CEST #

I'm answering your question on the latest icalds blog post at http://blogs.sun.com/openomics/entry/releasing_icalds_2_1#comments since I'm been sending that URL around lately.

Posted by Frederic Pariente on September 10, 2009 at 03:33 AM CEST #

Hi Frederic.

I'm using your tool right now. I did not have to do more test until now, and everything is working good.

Many Thanks for the job.

BYe...

Posted by Manuel on October 19, 2009 at 11:08 AM CEST #

You say : "you can directly sync a 3G device to Sun Calendar Server through SyncML".

Can you explain how could I natively sync my nokia with a Sun Calendar Server ?

Do I need CalDAV support and icalds, or can I do it natively?

Thanks

Posted by Romain on April 25, 2010 at 05:53 PM CEST #

Romain, you need to talk to your IT guys to check whether they have a SyncML gateway running --essentially, they need to give you a URL to point to. Then, browse the Nokia forums for help on how to configure your cellphone. HTH, Frederic.

Posted by Frederic Pariente on April 26, 2010 at 10:39 AM CEST #

Frederic,
I'm the IT guy ;-)... But I admit I didn't pay a lot of attention to our sun calendar server... It's an aging v6.2, maybe that's why I've never seen a syncml connector... ?

Posted by Romain on April 26, 2010 at 10:47 AM CEST #

Romain, I would point you to this forum :
http://forums.sun.com/forum.jspa?forumID=737. I don't know myself enough about the product --I'm neither an admin nor a developer of the Sun Calendar-- to tell you how to set up a SyncML gateway for the Sun Calendar server. I just know it's possible b/c our IT guys have done it for our own installation. If you google "sun calendar syncml gateway", there are also some interesting links but again I do not know if this is what we Sun have in use. Good luck!

Posted by Frederic Pariente on April 27, 2010 at 01:40 AM CEST #

Fréderic : Thanks for pointing me this... It's seem there is no native support for SyncML in Sun calendar server.
Although, there are third-parties connectors providing SyncML that might support WCAP backend... I might turn to developing an ActiveSync connector based on Zpush for WCAP.

I don't give up on SyncML, I'll give a try to Funambol and maybe add a WCAP connector for it...

Posted by Romain on April 27, 2010 at 03:15 AM CEST #

Post a Comment:
  • HTML Syntax: NOT allowed
About

How open innovation and technology adoption translates to business value, with stories from our developer support work at Oracle's ISV Engineering.

Subscribe

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
5
6
8
9
10
11
12
13
16
17
18
19
20
21
23
24
25
26
27
28
29
30
   
       
Today
Feeds