Calendar Syncing with iPhone and Mozilla Sunbird or Thunderbird/Lightning

0 comments

Posted on 7th December 2010 by admin in How-To | Mobile | Tech

, , , , , , , , , ,

After an unacceptably long vacation from blogging, I’m back. And I’ll try to post goodies here more often!

Today’s post is a rant followed by a technical solution that hopefully some will find useful. You can skip past the rant by clicking here ;)

The Rant: Cloud Storage and Sync

iPhoneI tend to use a lot of open source software. It’s free, and it’s usually as well or better built than commercial software. It does sometimes require a bit of technical knowledge and troubleshooting though.

I also own an iPhone. In some ways, I really love it. I can check on all my websites, servers, social streams, emails, and calls from one compact gadget. From anywhere. However, the iPhone is unfortunately a very closed sort of platform. Apple controls all of the software available for the device, and chooses not to provide some seemingly basic features – like accessing files stored on the phone from your computer.

Now almost anybody you ask will say that you should just sync all your data to the cloud. Then you can access it from your computer easily (or from anywhere else). But I have a problem with that.

Cloud StorageWhen you sync your data to the cloud, you’re sending it to a server that’s controlled by a third party. Any of the following things can then happen:

  1. Some nosy admin on the other end can inadvertently or purposely start looking through your data. He could get fired, but only if his boss finds out.
  2. The third party could have its servers compromised, by hackers for instance. Oops! now bl4sterz.ru knows your every personal detail.
  3. By storing your data, the third party in a sense “owns” it. If they decide to start embedding ads in your data, or charging a monthly fee to use their service, what can you do about it?

For these sorts of reasons, I never send information to third parties on the web unless I’m basically comfortable with that information being publicly available to all. Yes, that means you, Facebook. And Twitter. Et cetera.

The Problem: iPhone/Lightning Calendar Sync, without the Cloud

OK, enough rant about cloud storage services. Here’s why this all came up:

Mozilla ThunderbirdAs I said before, I have an iPhone. I also use Mozilla’s Thunderbird email browser with a calendar plugin called Lightning to manage my appointments and such. I would like to have the calendar on the iPhone sync with Lightning. (Mozilla Sunbird is basically the same as Lightning for Thunderbird – it’s made by the same folks and has the same functionality. Sunbird just lacks the email client.)

If you Google how to do this, everyone says that you should sync both Lightning and the iPhone with Google calendar. But that’s a cloud solution: I don’t want Google to know all my appointments!

The Solution: Set Up Your Own CalDAV server

CalDAVFaced with this problem, I’ve worked out a nice solution: install your own CalDAV server. You can do this on either your own local network (more secure), or any webserver you have access to remotely (easier to share calendars with many people).

CalDAV is an implementation of a web standard called WebDAV which makes it easy to store files, calendars, addressbooks, and other information in a format that is easily readable by many devices and platforms. CalDAV specifically can identify users and store events – including recurring events and alerts. You can set up shared calendars, configure read-write access for different users to different calendars. In short, CalDAV can provide enterprise-level calendaring functionality much like Microsoft’s Exchange server.

There are a number of CalDAV servers available, both free and commercial. After assessing several, I went with DAViCal, an open source CalDAV server implementation built on top of Apache, Perl, PHP5, and PostgreSQL server. If you need to install this suite, you can grab a prepackaged distribution like the Bitnami stack, or install each package from the Linux shell if you’re comfortable doing so.

Tux WorkingThe details of how to install DAViCal depend on the operation system distribution you’re running on your server box. See the Distribution Specifics section of the DAViCal Installation Wiki. When I installed DAViCal, I ran into the following problems. I’m posting them here, as well as some tips, in hopes that they may save you some time:

  • If you’re installing in a shared server environment, you’ll need to change the hard-coded Postgre database name and username in davical/dba/create-database.sh. You may also need to manually specify the location of the AWL library in this script if it’s not in /usr/share/awl.
  • When running davical/dba/create-database.sh, pay attention to the output. Near the end, it will say something like “created user user with password password” – save these, as you will need them to log into DAViCal’s web administration interface later.
  • I ran into a problem where some of DAViCal’s installation Perl scripts wouldn’t run because I was missing some required Perl modules. When I tried installing them (yum install perl-DBD-Pg), I got “package not found”… until I checked /etc/yum.conf which had exclude= … perl* …. Removing the perl* fixed this issue :)
  • The Installation Wiki gives two methods to install DAViCal: as a directory on your server (example.com/davical) or as a VHost subdomain (davical.example.com). If you want this to work with iPhone, go the subdomain route – when I tried to tack on a directory in the iPhone CalDAV settings, it kept removing it.
     

    If you’re using an automated system like cPanel to manage your server VHosts, and hence don’t want to edit httpd.conf manually, just follow the directions for installing DAViCal in a directory (creating the symlink to davical/htdocs), and then create the subdomain in cPanel, but giving the symlink for the directory.

Once installed, visit davical.example.com in your web browser. You should see a login screen soliciting a username and password, or you may see a diagnostic screen with some details if your installation isn’t complete.

Log into DAViCal with the username and password the dba/create-database.sh script generated. In the menu up top, choose User Functions -> View My Details. At the bottom of this page, under Principal Collections, click Create Collection. This will basically create a new calendar you can subscribe to with a CalDAV client. Fill in the DAV Path and Display Name. Click Create.

Now, to subscribe to your new CalDAV, you’ll use the URL http://davical.example.com/caldav.php/username/DAVPath, where username is the username you used to log into the administrative interface for DAViCal, and DAVPath is what you set when creating the collection (previous paragraph).

iPhone CalendarOn the iPhone, you can subscribe to this calendar by chosing Settings -> Mail, Contacts, Calendars -> Accounts -> Add Account -> Other -> Calendars -> Add CalDAV Account. Server is your davical.example.com, User Name and Password are from your administrative account, and Description is any descriptive name you want appearing in your iPhone Calendar list. (Maybe the Display Name you chose in DAViCal admin?). Click Next: the iPhone will try to autodetect other settings. If it works, great! your calendar has been added. If not, click the Advanced Settings button that appears, then copy http://davical.example.com/caldav.php/username/DAVPath (see previous paragraph) into the Account URL.

In Lightning or Sunbird, right-click in the calendar list and choose New Calendar. Then, On the Network and Next. Choose CalDAV for the format, and enter http://davical.example.com/caldav.php/username/DAVPath (see two paragraphs ago) into Location. Hit Next. Enter your username and password. Now you should be subscribed to your CalDAV calendar!

Summary

The iPhone can sync many things very well indeed – music, email, even web browser bookmarks. But for open source calendar software, the only easy way is to use Google’s cloud service. If you’re unwilling to do that, however, rejoice: there is another way!

Running a CalDAV server like DAViCal is a great way to sync calendars across computers and mobile devices, and even to share calendars with friends. And if you’re still worried about the security of your data on a public server (even one that you own or control), you can run a CalDAV server on a local network. It just won’t be accessible for remote synchronization.

I hope this guide was useful to you. Feel free to leave your comments below.

  • Share/Bookmark

Twitter from PHP

1 comment

Posted on 16th June 2009 by admin in Tech | Web Development

, ,

A few months ago I broke down and joined Twitter. Pretty much the only reason is that I wanted to learn how to integrate Twitter into PHP web applications. Here’s what I found:

Twitter has a URL http://www.twitter.com/statuses/update.xml where you can POST a twitter update. The following HTML form will update your twitter status after asking you for your username and password:

<form action="http://twitter.com/statuses/update.xml" method="POST">
	<input type="text" name="status" />
	<input type="submit" value=""Tweet!" />
</form>

This is cool, but it would be nice to circumvent the password protection in a web application where you probably already have a user logged in and validated? Fortunately this is possible using HTTP headers: (please make sure you read my SECURITY NOTE below)

<form action='twitter.php' method='post'>
	<input type='text' name='status' />
	<input type='submit' value='tweet' />
</form>
<?php
	if($_POST['status']!="") {

		$data = "status=".stripslashes($_POST['status']);
		$fp = fsockopen("www.twitter.com", 80);
		$user = "twitter_username";
		$pass = "twitter_password";

		fputs($fp, "POST /statuses/update.xml HTTP/1.1\r\n");
		fputs($fp, "Host: www.twitter.com\r\n");
		fputs($fp, "Referer: None\r\n");
		fputs($fp, "Authorization: Basic ".
			base64_encode($user.":".$pass)."\r\n");
		fputs($fp, "Content-type: ".
			"application/x-www-form-urlencoded\r\n");
		fputs($fp, "Content-length: ". strlen($data) ."\r\n");
		fputs($fp, "Connection: close\r\n\r\n");
		fputs($fp, $data);

		while(!feof($fp))$str .= fgets($fp, 128);
		if(!strstr(" OK ",$str))
			echo "There was a problem posting your twitter update.";
		else echo "twitter update posted successfully!";
	}
?>

SECURITY NOTE:

Please notice that the code above sends the username and password hash unencrypted over a plaintext HTTP pipe. The password hash is thus vulnerable to rainbow table attacks.

A better solution uses HTTPS with cURL. This way, the username & password hash info don’t have to be sent plaintext:

<form action='twitter.php' method='post'>
	<input type='text' name='status' /> <input type='submit' value='tweet' />
</form>
<?php
	if($_POST['status']!="") {
		$url = "https://twitter.com/statuses/update.xml";
		$user = "twitter_username";
		$pass = "twitter_password";

		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_POST, true);
		curl_setopt($ch, CURLOPT_HEADER, true);
		curl_setopt($ch, CURLOPT_USERPWD, $user.":".$pass);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_POSTFIELDS,
			"status=".stripslashes($_POST['status']));

		ob_start();
		curl_exec($ch);
		$str = ob_get_contents();
		ob_end_clean();
		curl_close($ch);

		if($str=="" || strstr($str,"<error>"))
			echo "There was a problem posting your twitter update.";
		else echo "twitter update posted successfully!";
	}
?>

Since I’ve started using twitter I’ve found that it’s very useful for companies and organizations that want to get messages out to lots of people quickly. You can even get twitter updates by phone using SMS!

Happy tweeting!

  • Share/Bookmark

PHP ICO to PNG conversion

12 comments

Posted on 17th February 2009 by admin in Computers | Web Development

, , , , ,

A few posts ago I wrote about using a PHP class to convert an ICO image to a PNG (or GIF or JPG). I just discovered a bug in the class.

I ran into a problem where some red and orange ICO images turned blue during the conversion. Reading this forum post made me realize that the red and blue values were switched somewhere in class.ico.php. With some experimentation I found it:

In class.ico.php, lines 264-267 need to be changed from

$c[$i] = $this->AllocateColor($im, $this->formats[$index]['colors'][$i]['red'],
         $this->formats[$index]['colors'][$i]['green'],
         $this->formats[$index]['colors'][$i]['blue'],
         round($this->formats[$index]['colors'][$i]['reserved'] / 255 * 127));

to

$c[$i] = $this->AllocateColor($im, $this->formats[$index]['colors'][$i]['blue'],
         $this->formats[$index]['colors'][$i]['green'],
         $this->formats[$index]['colors'][$i]['red'],
         round($this->formats[$index]['colors'][$i]['reserved'] / 255 * 127));

(Note that the blue and red values are indeed switched.) After changing this, it works like a charm for me.

  • Share/Bookmark

Facebook profile box tips

18 comments

Posted on 17th February 2009 by admin in Computers | Web Development

, , ,

As mentioned in my previous post, I’ve been finishing up a facebook application, My Sites. Now that it’s done, I thought I’d post a few tips on how to add profile boxes to your facebook application, since I found it maddeningly complicated.

For the non-facebook-savy, a profile box is a small box that applications can add to your profile’s “wall” or “boxes” tabs. They’re meant to provide a quick glimpse of what’s happening with the application.

I’m assuming that you keep a database of Facebook users, and you want to display something about them in the profile box.

The basic code for adding a profile box is below, annotated with copious comments. This is in PHP code, you can do it in other languages, but it’s what I use. Pop this code into a daily cron for example, and you’re good to go.

<?php
// This code connects to the facebook API.
@require_once 'facebook-platform/php/facebook.php';
$appapikey = 'facebook app api key';
$appsecret = 'facebook app api secret';
$facebook = new Facebook($appapikey, $appsecret);

// This code connects to your own database.
$BASEURL = "http://example.com/path/to/facebook/app";
$connection = @mysql_connect("server","username","password");
if(!$connection)die("Can't connect to the database at this time.");
$res = @mysql_select_db("database");
if(!$res)die("Site database doesn't seem to exist.");

// This code cycles through each user in the database
$sql="SELECT * FROM users";
$data=@mysql_query($sql);
while($user=mysql_fetch_assoc($data)) {
     // You can, of course, query your database to build these strings
     $WideBox = "Whatever you want a profile box on the 'boxes' tab to say.";
     $MobileBox = "Whatever you want a profile box accessed by a mobile device to say.";
     $NarrowBox = "Whatever you want a profile box on the 'wall' tab to say.";

     // This is the API call, it sets the user's profile box content:
     $facebook->api_client->profile_setFBML(
          NULL,        // This is the markup, set to NULL for 'FBML'
          $user['id'],  // ID number of the user whose profile box you want to set
          $WideBox,    // Wide box content for 'boxes' tab
          NULL,        // Deprecated, should always be NULL
          $MobileBox,  // Box content for mobile devices
          $NarrowBox   // Narrow box content for 'wall' tab
     );
}
// Clean up the connection
@mysql_close($connection);
?>
  • Share/Bookmark

ICO images in FaceBook profile boxes

1 comment

Posted on 9th February 2009 by admin in Computers | Web Development

, , , , , , , ,

So I’ve been developing a FaceBook application, My Sites. It let’s you bookmark websites you like and share them with your friends.

The Problem

When a FaceBook application tries to add HTML to someone’s profile box, it can add images, but only in JPG, GIF, or PNG formats. For most uses this is fine, but I needed to add a favicon next to each website in a list, and ICO format isn’t allowed.

The Solution

Using a free php class that can import ICO images to a GD image resource, I converted the favicons to PNGs. Now FaceBook is all happy. Download a ZIP of the icon class here, or directly from PHPclasses.org.

[EDIT: please see my post on the important bug fix]

The Code

Here’s how you use the class:


<?php
error_reporting(0);
require("ico.class.php");
$f = "http://www.google.com/favicon.ico";
$i = new Ico($f);
if(!($r=$i->GetIcon(0))) die("Could not load ICO.");
else {
          header("Content-Type: image/png");
          imagepng($r);
}
?>
  • Share/Bookmark

WP SlimStat