/** * Export schedules of Outlook(!=express) by iCal format. * * usage: * cscript.exe ol2ics.js [/folder:folder_path] outfile.ics * * Tried env. * Outlook 2003 SP3 + XP Prof SP2(ja) * Outlook 2007 SP1 + Vista Ultimate SP1 x64(ja) * * TODO: * o recurring items.. */ var exp = new ScheduleExporter(); var fn_out = "sch_export.ics"; var folder_path = null; var args = WScript.Arguments.Unnamed; if( args.length >= 1 ) { fn_out = args(0); } var opt = WScript.Arguments.Named; if( opt.Item("folder") ) { folder_path = opt.Item("folder") ; } exp.export2ical( fn_out , "utf-8" , folder_path ); function ScheduleExporter() { this.Manufacturer = "homemade"; this.Name = "ScheduleExporter"; /* Outlook - OlDefaultFolders */ var olFolderCalendar = 9; /* Outlook - OlItemType */ var olAppointmentItem = 1; var olContactItem = 2; var olDistributionListItem = 7; var olJournalItem = 4; var olMailItem = 0; var olNoteItem = 5; var olPostItem = 6; var olTaskItem = 3; /* ADODB.Stream - SaveOptionsEnum */ var adSaveCreateNotExist = 1; var adSaveCreateOverWrite = 2; /* ADODB.Stream - StreamTypeEnum */ var adTypeBinary = 1; var adTypeText = 2; /* ADODB.Stream - StreamWriteEnum */ var adWriteChar = 0; var adWriteLine = 1; ScheduleExporter.prototype.export2ical = function( fn_out , charset , folder_path ) { var app = new ActiveXObject("Outlook.Application"); var ns = app.GetNamespace("MAPI"); var folders = []; if( folder_path == null ) { folders.push( ns.GetDefaultFolder(olFolderCalendar) ); } else { folders = this.find_folder( folder_path , ns ); } var st = new ActiveXObject("ADODB.Stream"); st.type = adTypeText; st.charset = charset; st.open(); st.WriteText( "BEGIN:VCALENDAR" , adWriteLine ); st.WriteText( "METHOD:PUBLISH" , adWriteLine ); st.WriteText( "PRODID:-//" + this.Manufacturer + "//" + this.Name + "//EN" , adWriteLine ); st.WriteText( "VERSION:2.0" , adWriteLine ); for( var i = 0; i < folders.length ; i++ ) { this.dump_folder( folders[i] , st ); } st.WriteText( "END:VCALENDAR" , adWriteLine ); // BOM... var pos = 0; if( charset.match( /^utf-8$/i ) ) { pos = 3; } st.Position = 0; st.Type = adTypeBinary; st.Position = pos; var bin = st.Read(); st.Close(); var stw = new ActiveXObject("ADODB.Stream"); stw.Type = adTypeBinary; stw.Open(); stw.Write( bin ); stw.SaveToFile( fn_out , adSaveCreateOverWrite ); stw.Close(); return true; } ScheduleExporter.prototype.find_folder = function( path , root ) { var rc = []; var traverse = function( begin ) { var folders = begin.Folders; for( var i = 1 ; i <= folders.Count ; i++ ) { var folder = folders(i); if( folder.FolderPath && folder.FolderPath == path ) { rc.push( folder ); } traverse( folder ); } }; traverse( root ); return rc; } ScheduleExporter.prototype.dump_folder = function( folder , st ) { var items = folder.Items; var now = new Date(); for( var i = 1; i <= items.Count ; i++ ) { var item = items(i); if( item.End >= now ) { this.dump_one( item , st ); } } } ScheduleExporter.prototype.dump_one = function( item , st ) { var dt_start = new Date( ""+item.Start ); var dt_end = new Date( ""+item.End ); var dt_creation = new Date( ""+item.CreationTime ); st.WriteText( "BEGIN:VEVENT" , adWriteLine ); if( item.AllDayEvent ) { st.WriteText( "DTSTART;VALUE=DATE:" + this.by_date(dt_start) , adWriteLine ); st.WriteText( "DTEND;VALUE=DATE:" + this.by_date(dt_end) , adWriteLine ); } else { st.WriteText( "DTSTART:" + this.ical_date_utc(dt_start) , adWriteLine ); st.WriteText( "DTEND:" + this.ical_date_utc(dt_end) , adWriteLine ); } st.WriteText( "LOCATION:" + item.Location , adWriteLine ); st.WriteText( "UID:" + item.EntryID , adWriteLine ); st.WriteText( "DTSTAMP:" + this.ical_date_utc(dt_creation) , adWriteLine ); st.WriteText( "SUMMARY:" + item.Subject , adWriteLine ); // ignore item.Body. // coz, It raises alert dialog to acquire permission for access secure infos. // so. DESCRIPTION will not be buried. //st.WriteText( "DESCRIPTION:" + item.Body.replace(/\r?\n/g , "\\n") , adWriteLine ); st.WriteText( "END:VEVENT" , adWriteLine ); } ScheduleExporter.prototype.zpad = function( v , n ) { var s = "0000" + v; return s.substr( s.length - n ); } /* * YYYYMMDD(Local) */ ScheduleExporter.prototype.by_date = function( dt ) { var y = dt.getFullYear(); var m = dt.getMonth()+1; var d = dt.getDate(); m = this.zpad( m , 2 ); d = this.zpad( d , 2 ); return y + m + d; } /* * YYYYMMDDTHHMISSZ (UTC) */ ScheduleExporter.prototype.ical_date_utc = function( dt ) { var y = dt.getUTCFullYear(); var m = dt.getUTCMonth()+1; var d = dt.getUTCDate(); var h = dt.getUTCHours(); var min = dt.getUTCMinutes(); var s = dt.getUTCSeconds(); m = this.zpad( m , 2 ); d = this.zpad( d , 2 ); h = this.zpad( h , 2 ); min = this.zpad( min , 2 ); s = this.zpad( s , 2 ); return y + m + d + "T" + h + min + s + "Z"; } return this; }