So I use rsync to keep a remote directory up to date

On an older post about WinSCP Kamil Grabowski asked if I’d used rsync to keep remote files in sync.

I have, and use it more often than winscp or sshfs.

rsync is basically a smart copy utility – it can copy (sync) files between local or remote directories, and it will copy on the changed portions of files.

You can use it as a single invocation:

rsync -avr localdir remoteuser@remotehost:remotedir

You can also do it in a loop (but note that if you haven’t set up your SSH keys, you’ll be prompted for a password each time…):

while true; do rsync -avr localdir remoteuser@remotehost:remotedir; sleep 5; done

If you want it to not make a connection unless there are new files, you need to get a bit more complex:

set source=SOURCE_DIR
touch -t 197001010000 last # make a placeholder file as of 1970 so we can find newer files
while true
  if [ "`find $source -newer last -print`" ]
    touch last
    rsync -avrz $source $dest
    echo -ne .
  sleep 5

Leave a Comment

So I Deleted a Calendar on my iPhone

I didn’t expect it would be difficult to delete a calendar from my iPhone, but it was.

I recently upgraded to iPhone OS 3.0 (took me a while, I know), and began using the built-in calendar functionality to sync with Google Calendar. I had previously been using an application called “NemusSync”, so now I had too copies of my google calendar information displayed in the calendar application. I wanted to get rid of the old one, but there doesn’t appear to be a UI for it, and doing a Google search on how to delete an iphone calendar wasn’t immediately helpful.

This method works for jailbroken phones, and is probably more involved than you want it to be, but it is what I did. It requires SSH, Python, and the sqlite3 module (all installed via Cydia).

Also, I’m only hiding the extra calendar – the data is still on the phone, but I don’t have enough data there that I’m worried about it – you could use the same method to actually delete the data from the database if you want.

Here we go, with comment lines beginning with ‘#’:

# connect to your phone, enter password when prompted

# start the Python interpreter
/var/root# python
Python 2.5.1 (r251:54863, xx/xx/xx, xx:xx:xx)
[GCC 4.2.1 (Based on Apple Inc. build 5555)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

# import the SQLITE db module, and connect to the database
>>> import sqlite3
>>> name='/private/var/mobile/Library/Calendar/Calendar.sqlitedb'
>>> c = sqlite3.connect( name )
>>> def printall( x ):
... i = 0
... for r in x.fetchall():
... i+= 1
... print i, r
>>> printall( c.execute( 'select * from Calendar' ))
1 (1, 1, u'Default', 0, 1, 0, -1, -1, -1, None, None, None, None, None, None, None)
2 (2, 1, u'local', 0, 0, 0, 127, 127, 127, 1, None, 0, None, None, None, None)
3 (3, 1, u'', 0, 0, 0, 163, 41, 41, 1, None, None, None, None, None, None)
4 (4, 2, u'', 0, 0, 0, 163, 41, 41, 0, None, 0, u'', u'MY_ID', None, None)

>>> printall( c.execute( 'update calendar set hidden=1 where rowid=3'))
>>> c.commit()

And that should hide the old calendar from the Calendar application.

Note that I did have to explore the database and figure out how to inspect the schema of the sqlite database to find the table and column names. Preserving that information here for the collective memory…

>>> c.execute( '''show tables''' )
Traceback (most recent call last):
File "", line 1, in
sqlite3.OperationalError: near "show": syntax error

# shoot, no "show tables". ...googling... OK:
>>> printall( c.execute( 'select name from sqlite_master where type="table";'))
1 (u'_SqliteDatabaseProperties',)
2 (u'Store',)
3 (u'sqlite_sequence',)
4 (u'Alarm',)
5 (u'AlarmChanges',)
6 (u'Recurrence',)
7 (u'RecurrenceChanges',)
8 (u'OccurrenceCache',)
9 (u'OccurrenceCacheDays',)
10 (u'GCalAccounts',)
11 (u'GCalCalendars',)
12 (u'GCalState',)
13 (u'GCalEvents',)
14 (u'Calendar',)
15 (u'CalendarChanges',)
16 (u'Event',)
17 (u'EventChanges',)
18 (u'EventExceptionDate',)
19 (u'Task',)
20 (u'TaskChanges',)
21 (u'Attendee',)
22 (u'AttendeeChanges',)
23 (u'Participant',)

# Calendar looks good...
>>> printall( c.execute( "describe calendar" ))
Traceback (most recent call last):
File "", line 1, in
sqlite3.OperationalError: near "describe": syntax error

# dang, no "describe TABLE". ...googling... OK
>>> printall( c.execute( "PRAGMA table_info(Calendar)" ))
1 (0, u'ROWID', u'INTEGER', 0, None, 1)
2 (1, u'store_id', u'INTEGER', 0, None, 0)
3 (2, u'title', u'TEXT', 0, None, 0)
4 (3, u'read_only', u'INTEGER', 0, None, 0)
5 (4, u'hidden', u'INTEGER', 0, None, 0)
6 (5, u'immutable', u'INTEGER', 0, None, 0)
7 (6, u'color_r', u'INTEGER', 0, None, 0)
8 (7, u'color_g', u'INTEGER', 0, None, 0)
9 (8, u'color_b', u'INTEGER', 0, None, 0)
10 (9, u'color_is_display', u'INTEGER', 0, None, 0)
11 (10, u'type', u'TEXT', 0, None, 0)
12 (11, u'supported_entity_types', u'INTEGER', 0, None, 0)
13 (12, u'external_id', u'TEXT', 0, None, 0)
14 (13, u'external_mod_tag', u'TEXT', 0, None, 0)
15 (14, u'external_id_tag', u'TEXT', 0, None, 0)
16 (15, u'external_rep', u'BLOB', 0, None, 0)

# that "hidden" column looks useful...

Comments (2)

So I Found a Windows SSHFS

It’s from Japan, and is called Dokan SSHFS. It works well.

Some limitations – it will mount the remote filesystem as a drive, so you need to assign a drive letter to each remote filesystem you want to mount. It saves connection info, but not your password or key passphrase. When you type those, it will display them in cleartext, so be aware.

This beats the WinSCP periodic update model for my use cases – however, it does mean that saving files can be slow, depending on your network bandwidth and latency.

For Unix/Linux, you can use the original SSHFS, as I described in another blog post.

Comments (3)

So I Considered AppStore vs. Cydia

From ChaZg33k on So I Made My iPhone Say Hello, World…

Why would you want to use the App Store when you could submit to Cydia?

Hmm. Troll, or serious question? Guess I’ll respond as a serious question, because I have something serious to say.

Cydia is cool. But the AppStore reaches more iPhones (all jailbroken and all “stock” iPhones) – and most people I see with an iPhone don’t have it jailbroken (and yes, I’ve been asking – current ratio is about 10:1).

Also, there’s a strange behavior with iPhone users – they actually seem willing to PAY for software in the AppStore! <NY Times>.

Given the prevalence of Crackulous, I don’t know that the same holds true for many Cydia users (n.b., I use Cydia, but not Crackulous, and yes, I realize that there are fair use arguments for tools like that, and that the DMCA also has a few arguments to make).


P.S. Just about ready to submit my first app to the AppStore (nothing fancy, though it made me build infrastructure and experience for other projects I have going), then hoping to begin posting more about details, and should be following on with more interesting apps shortly!

Leave a Comment

So I Took a Screenshot on my G1…Here’s the Howto

So I compared my iPhone and my G1, and included notes on how to take a G1 screenshot, but it turns out there was another step: installing the appropriate drivers, and enabling debug on the G1.

So, to take G1 screenshots:

  1. Turn on USB debugging on the G1: Settings | Applications | Development | USB debugging
  2. Download and install the Android SDK
  3. Download and unzip the Android USB device drivers (for Windows – for Linux, see the additional instructions on the DevelopAndDebug page).
  4. Connect the device via USB, and choose “Install from a list or specified location” and choose where you unzipped the file. If you’ve already gone through this and Windows doesn’t prompt you anymore, you’ll need to open Control Panel | Administrative Tools | Computer Management | Device Manager, go down to Other Devices and choose the Android phone, then right click Properties, and choose Update Driver, then browse to the specific location…
  5. From the Android SDK, start tools/ddms.bat
  6. Your G1 should appear as the only device in the left-hand side.
  7. You can then press Ctrl-S (Device | Screen Capture) to capture a screenshot.
    G1 screenshot
  8. Breathe a sigh of relief

Comments (11)

So I used sshfs to Mount a Remote Filesystem

This is the one Linux way to edit files remotely as if they were local. For a Windows approach, see my post on WinSCP. There’s also a Windows sshfs called Dokan SSHFS.

sshfs is a user-space Linux filesystem that makes an ssh connection look like a local filesystem.

It’s trivial to use:

  1. As root (or using sudo) add your user to the ‘fuse’ group:

    # adduser butler fuse
    Adding user `butler' to group `fuse' ...
    Adding user butler to group fuse

  2. Start a new shell as the desired user (to get the updated group list), make a mount point, and start sshfs. Note that sshfs will prompt you to accept the remote key (not shown) if this user hasn’t previously connected to this remote account.

    $ mkdir soi
    $ sshfs soi's password:
    $ ls soi/images
    changeDirectories.jpg keepRemoteSynced.jpg updatingFiles.jpg
    directoriesSynced.jpg session.jpg watchForChanges.jpg
    firstSession.jpg updateFiles.jpg

  3. Read and update files as if they were local – but with some transfer lag…

If you don’t want to deal with the lag every time you read or write the file, you’ll probably want to use scp or rsync to copy the files over when you need them on the remote machine – and you’ll probably want to use ssh-agent and ssh-add to set up key-based authentication, so you don’t have to type your password every time. You can even put the scp or rsync calls in your Makefile…

Comments (1)

So I used WinSCP to Keep a Remote Directory Up-to-Date

Mononofu reminded me I hadn’t talked about how to keep remote directories in sync. This is the windows version. For a Linux version, see my post on sshfs.

So, to work on files locally on Windows, but have them automatically copied to a remote directory, use WinSCP.

  1. Download WinSCP 4.17 and install it
  2. Run WinSCP
  3. Enter info to connect to the remote host (like your iphone)Session parameters
  4. On your first connect, WinSCP won’t recognize the key of the remote system, so just accept it. If you see this prompt later, it either means your remote system got a new key (e.g., reflashed the phone and re-jailbroke it), or somebody could be trying to intercept your communications. Prompt to accept remote host key
  5. Change directories to the local and remote directories you want to keep synced. Change directories
  6. Choose Commands | Keep Remote Directory up to Date (Ctrl-U). Keep Remote Directory up to Date (Ctrl-U)
  7. Choose options for synchronization, and do a full synchronization to get things started. Watch for changes
  8. Make changes to the files on your local machine. Update local files
  9. WinSCP notices the changes and pushes them to the remote machine. Updating files
  10. The directories are kept in sync. Directories synced

Comments (5)

So I wonder which is more open? G1 or iPhone

At first blush, the G1 is obviously more open than the iPhone – open source platform, open SDK from day 1, and you can install software from anywhere just by selecting a menu option.

But this software runs in a Java sandbox. You don’t appear to have access to the operating system outside the sandbox.

And I have a jailbroken iPhone. I can ssh into my phone. I can use the phone without a SIM card (G1 goes into “emergency calls only” mode). I can modify startup scripts. I can write applications to do anything on the phone. I can change anything I want to on the phone, as a Simple Matter Of Programming. Is the G1 that open? Not the Android platform – the actual, G1 device in my hands…

Of course, as a platform, Android is much more open than iPhone OS. But the actual device? So far, I’m saying a jailbroken iPhone…

Leave a Comment

So I Compared a T-Mobile G1 vs an iPhone

I’ll continue to update this as I continue to learn about both phones, but I’ll start with some first impressions.

  • The G1 is noticeably bigger, but not bad.

    It’s bigger than the iPhone, bigger than my RAZR VR3, thinner than my wife’s old T-Mobile Wing, but way smaller than my Zaurus c860. It fits in a shirt pocket or pants pocket (though my wife is concerned about it being tight in her jeans pockets).

    It meets my size criteria, though I’d like it to be smaller – I forget the iPhone is in my pocket, not likely to forget the G1.

  • The bend of the G1 isn’t bad. I was really concerned from the pictures of the bent-up bottom of the phone, but you don’t notice it, it isn’t bad to hold either in portrait or landscape. Not a problem.
  • The iPhone screen is noticeably larger, and a bluer white. The G1 screen is brighter, and a bit warmer (more yellow) white.
  • Android needs a review of “small screen” mentality. Apple got this right (very right) in that whatever application is presenting content to the user gets the whole screen. Smaller-than-screen windows should be rare, and only for very small announcements.

    There are lots of places Android uses sub-screen windows, often presenting large amounts of content without making full use of the available screen real estate. This is present in basic functionality – like the Applications tab not using the whole screen – and applications using dialog boxes.

    You can really see this by going into the Settings|About section – all the Legal documents are presented in a centered dialog box, appearing over the background window, even though they have pages and pages of content. If you open the DMCA info, you get a web page that is scrolled horizontally half off this tiny dialog box because of navigation controls on the left side (but they’re not even visible because the page is scrolled down past them). Really obnoxious. Kudos to Apple.

    Oh, and one more example: setting up a Wireless access code. the G1 pops up a dialog box (again, smaller than screen size) for you to enter your key. And you have to open the keyboard, rotating to landscape mode, to enter it, because there is no onscreen touch keyboard. Then you type the key, and there is a half-exposed control at the bottom of the dialog box. If you scroll the dialog box up a bit, you can see that it is a checkbox to display the key as you’re typing it. If the dialog took advantage of the whole screen, you wouldn’t need to scroll to see this option.

  • Android is much less aware of its device than the iPhone is. No, I’m not trying to anthropomorphize the phones.

    When you tip the iphone, it (usually) rotates to landscape. Touch is integrated throughout the iPhone system, to go back, to select options, etc. You always interact by touching the screen.

    I haven’t found anything on the G1 that recognizes when I’m holding it landscape unless I open the keyboard. Then everything is landscape, even if I’m still holding the phone vertically. The only way to rotate the browser to landscape/wide-screen viewing is to open the keyboard.

    With Android, you go to the home screen by pushing the off-center home button. You get menus by pressing the menu button. You go back by pressing the back button. These functions are never presented on screen for a touch. I find myself constantly wondering, “How to I get back to that last window? Oh, yeah, the button”, whereas with the iPhone, it’s presented where your focus is, on the screen. I’m always forgetting what functions need the menu button, which need home, and which need back.

    Now, I realize that onscreen controls cost screen real estate (not as much as the “dialog boxes” do, though!). Maybe I’ll remember the G1 controls more naturally later, but for now, the physical buttons aren’t helping usability.

    And sometimes, things you really should be able to touch can’t be selected by touch – in the google legal information, you can’t touch-to-select a link until you’ve touched the trackball, then you can touch to select.

  • Apple’s browser is easier to use. The zoom & scroll is easier than the G1, thanks to the multitouch interface. Android could do better than its clunky buttons even without a touch screen, but for now it’s clunky.
  • To take a screenshot on an iPhone: hold down the “sleep” button and press and release the “home” button. It saves the screenshot to the Photos directory.

    To take a screenshot on the G1: connect the G1 via USB, install the SDK, run DDMS, select your handset, and press Ctrl-S, then save the image. ( *sigh*

Comments (3)

So I Had to Force Reset (Shutdown) my G1

When I turned on my T-Mobile G1 phone this morning, it showed a picture of a big triangle with an exclamation point inside it, and a G1 lying flat on its back.

It was completely unresponsive.

I tried holding down the power-off (end) button, alone and in combination with the various other buttons, but didn’t find anything that drew a response. Plugging the phone in to a USB cable connected to a computer caused the computer to recognize there was a USB device.

I tried scanning the “Tips and Tricks” booklet that came with the phone. Nothing. The user manual? Nada.

Finally, consulting the modern Oracle of Delphi (Google, that is), I found the answer:

Solution: Hold the Home and Back buttons for a few seconds (nothing happens) then release (and the phone restarts).


For what it’s worth, the battery level was at 5% when it completed rebooting. I guess the phone didn’t like having its battery get really low overnight?

Comments (2)