├── utils ├── discount └── markdown │ └── License.text ├── examples ├── arrow-down.png ├── arrow-right.png ├── configExample.png ├── .gitignore ├── FontList.as ├── font-list.txt ├── Makefile ├── cmdStdoutToPNG.m ├── generateExamplesOutput.py ├── examples.css ├── generateExamplesHTML.py └── cmdStdoutToHTML.m ├── tests ├── regression │ ├── ansihelper.pyc │ ├── ansihelper.py │ ├── integrationRegressionTests.py │ └── integrationRegressionTestCommands.txt └── unit │ ├── allTests.h │ ├── EventsTest.h │ ├── allTests.m │ ├── TestInfo.h │ ├── TestInfo.m │ ├── IcalBuddyUnitTest.h │ ├── EventsTest.m │ ├── IcalBuddyUnitTest.m │ ├── UnitTest.m │ └── UnitTest.h ├── faq-style.css ├── .gitignore ├── IcalBuddyAutoUpdaterDelegate.h ├── readme.md ├── HGCLIAutoUpdaterDelegate.h ├── ABRecord+HGAdditions.h ├── calendarStoreImport.h ├── HGCLIUtils.h ├── IcalBuddyAutoUpdaterDelegate.m ├── HGDateFunctions.h ├── icalBuddyArgs.h ├── deployment-files ├── exampleLocalizationFiles │ ├── english-icalBuddyLocalization.plist │ ├── japanese-icalBuddyLocalization.plist │ ├── hungarian-icalBuddyLocalization.plist │ ├── chinese-icalBuddyLocalization.plist │ ├── finnish-icalBuddyLocalization.plist │ ├── german-icalBuddyLocalization.plist │ ├── dutch-icalBuddyLocalization.plist │ ├── italian-icalBuddyLocalization.plist │ ├── polish-icalBuddyLocalization.plist │ ├── french-icalBuddyLocalization.plist │ ├── latin-icalBuddyLocalization.plist │ └── spanish-icalBuddyLocalization.plist ├── example-icalBuddyConfig.plist ├── readme.txt ├── uninstall.command └── install.command ├── calendarStoreMock ├── mockHelperFunctions.h ├── mockHelperFunctions.m └── MockCalCalendarStore.m ├── icalBuddyFunctions.h ├── testRunner.m ├── todo.markdown ├── icalBuddyFormatting.h ├── HGUtils.h ├── HGCLIAutoUpdaterDelegate.m ├── icalBuddyL10N.h ├── ABRecord+HGAdditions.m ├── HGCLIAutoUpdater.h ├── icalBuddyPrettyPrint.h ├── HGCLIUtils.m ├── icalBuddyL10N.m ├── icalBuddyDefines.h ├── HGUtils.m ├── icalBuddyLocalization.pod └── Makefile /utils/discount: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkaluta/icalBuddy64/HEAD/utils/discount -------------------------------------------------------------------------------- /examples/arrow-down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkaluta/icalBuddy64/HEAD/examples/arrow-down.png -------------------------------------------------------------------------------- /examples/arrow-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkaluta/icalBuddy64/HEAD/examples/arrow-right.png -------------------------------------------------------------------------------- /examples/configExample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkaluta/icalBuddy64/HEAD/examples/configExample.png -------------------------------------------------------------------------------- /tests/regression/ansihelper.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkaluta/icalBuddy64/HEAD/tests/regression/ansihelper.pyc -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | # ignored patterns 2 | 3 | # OS X junk 4 | Icon* 5 | .DS_Store 6 | 7 | # jEdit temp files 8 | \#*# 9 | 10 | # generated files 11 | cmdStdoutToPNG 12 | cmdStdoutToHTML 13 | cmdStdout.png 14 | examples.html 15 | FontList.swf 16 | -------------------------------------------------------------------------------- /faq-style.css: -------------------------------------------------------------------------------- 1 | 2 | #main { 3 | width: 600px; 4 | margin: 30 auto 300 auto; 5 | word-wrap: break-word; 6 | } 7 | 8 | /* TOC: */ 9 | #main > * > ul { 10 | border: 1px solid black; 11 | background: #eee; 12 | padding: 10px 10px 10px 30px; 13 | margin-left: 0; 14 | } 15 | #main > * > ul li { 16 | margin-bottom: 4px; 17 | } 18 | 19 | p { 20 | } 21 | 22 | h1 { 23 | font-size: 28px; 24 | } 25 | 26 | h2 { 27 | font-size: 18px; 28 | margin-top: 30px; 29 | } 30 | 31 | pre { 32 | border: 1px dotted black; 33 | background: #eee; 34 | padding: 10px; 35 | } 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ignored patterns 2 | 3 | # compiler-generated 4 | *.dSYM 5 | icalBuddy*.plist 6 | ANSIEscapeHelper.plist 7 | HG*.plist 8 | IcalBuddy*.plist 9 | 10 | # OS X junk 11 | Icon* 12 | .DS_Store 13 | 14 | # jEdit temp files 15 | \#*# 16 | 17 | # generated files 18 | deployment 19 | changelog.* 20 | icalBuddy 21 | testRunner 22 | testIcalBuddy 23 | icalBuddy.1 24 | icalBuddyLocalization.1 25 | icalBuddyConfig.1 26 | Manual-*.pdf 27 | usage.txt 28 | 29 | # temp files 30 | test.m 31 | a.out 32 | testConfig.plist 33 | log.txt 34 | tests/regression/*.log 35 | 36 | # other 37 | deploymentScpTarget 38 | .hg* 39 | -------------------------------------------------------------------------------- /examples/FontList.as: -------------------------------------------------------------------------------- 1 | package { 2 | 3 | import flash.display.Sprite; 4 | import flash.text.Font; 5 | import flash.text.FontType; 6 | import flash.text.FontStyle; 7 | import flash.external.ExternalInterface; 8 | 9 | public class FontList extends Sprite 10 | { 11 | public function FontList() 12 | { 13 | ExternalInterface.call('populateFontList', getDeviceFonts()); 14 | } 15 | 16 | public function getDeviceFonts():Array 17 | { 18 | var embeddedAndDeviceFonts:Array = Font.enumerateFonts(true); 19 | 20 | var deviceFontNames:Array = []; 21 | for each (var font:Font in embeddedAndDeviceFonts) 22 | { 23 | if (font.fontType == FontType.EMBEDDED 24 | || font.fontStyle != FontStyle.REGULAR 25 | ) 26 | continue; 27 | deviceFontNames.push(font.fontName); 28 | } 29 | 30 | deviceFontNames.sort(); 31 | return deviceFontNames; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/font-list.txt: -------------------------------------------------------------------------------- 1 | American Typewriter 2 | Andale Mono 3 | Apple Chancery 4 | Apple LiGothic Medium 5 | Apple LiSung Light 6 | Apple Symbols 7 | AppleGothic 8 | AppleMyungjo 9 | Arial 10 | Arial Black 11 | Arial Narrow 12 | Ayuthaya 13 | Baskerville 14 | BiauKai 15 | Big Caslon 16 | Brush Script MT Italic 17 | Chalkboard 18 | Chalkduster 19 | Charcoal CY 20 | Cochin 21 | Comic Sans MS 22 | Copperplate 23 | Courier 24 | Courier New 25 | Didot 26 | Euphemia UCAS 27 | Futura 28 | Futura Condensed 29 | GB18030 Bitmap 30 | Geneva 31 | Geneva CY 32 | Georgia 33 | Georgia Italic 34 | Gill Sans 35 | Hei 36 | Heiti SC 37 | Heiti TC 38 | Helvetica 39 | Helvetica CY 40 | Helvetica Neue 41 | Herculanum 42 | Hiragino Sans GB 43 | Hoefler Text 44 | Impact 45 | InaiMathi 46 | Kai 47 | Krungthep 48 | KufiStandardGK 49 | Lucida Grande 50 | Marker Felt 51 | Menlo 52 | Microsoft Sans Serif 53 | Monaco 54 | Optima 55 | Papyrus 56 | Plantagenet Cherokee 57 | Sathu 58 | Silom 59 | Skia 60 | Symbol 61 | Tahoma 62 | Thonburi 63 | Times 64 | Times New Roman 65 | Trebuchet MS 66 | Verdana 67 | Webdings 68 | Wingdings 69 | Wingdings 2 70 | Wingdings 3 71 | Zapf Dingbats 72 | Zapfino 73 | -------------------------------------------------------------------------------- /tests/unit/allTests.h: -------------------------------------------------------------------------------- 1 | // icalBuddy all unit tests 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import 31 | 32 | NSArray *getAllTests(); 33 | 34 | -------------------------------------------------------------------------------- /tests/unit/EventsTest.h: -------------------------------------------------------------------------------- 1 | // icalBuddy events test 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import "IcalBuddyUnitTest.h" 31 | 32 | @interface EventsTest : IcalBuddyUnitTest 33 | { 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /IcalBuddyAutoUpdaterDelegate.h: -------------------------------------------------------------------------------- 1 | // icalBuddy 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2012 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import 31 | #import "HGCLIAutoUpdaterDelegate.h" 32 | 33 | @interface IcalBuddyAutoUpdaterDelegate : HGCLIAutoUpdaterDelegate 34 | { 35 | } 36 | 37 | @end 38 | 39 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # icalBuddy 2 | 3 | This is a command-line utility that can be used to get lists of events and tasks/to-do's from the macOS calendar database (the same one Calendar.app uses). 4 | 5 | Read more at . 6 | 7 | Compiles and runs successfully on macOS 10.15.0 Catalina 8 | 9 | ## The MIT License 10 | 11 | Copyright (c) Ali Rantakari 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a copy 14 | of this software and associated documentation files (the "Software"), to deal 15 | in the Software without restriction, including without limitation the rights 16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | copies of the Software, and to permit persons to whom the Software is 18 | furnished to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in 21 | all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | THE SOFTWARE. 30 | -------------------------------------------------------------------------------- /HGCLIAutoUpdaterDelegate.h: -------------------------------------------------------------------------------- 1 | // CLI app auto-update code 2 | // 3 | // http://hasseg.org/ 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2010 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import 31 | 32 | @interface HGCLIAutoUpdaterDelegate : NSObject 33 | { 34 | NSString *appName; 35 | } 36 | 37 | - (id) initWithAppName:(NSString *)aAppName; 38 | 39 | @end 40 | 41 | -------------------------------------------------------------------------------- /ABRecord+HGAdditions.h: -------------------------------------------------------------------------------- 1 | // ABRecord+HGAdditions.h 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import 31 | 32 | @interface ABRecord (HGAdditions) 33 | 34 | - (NSInteger) hg_ageOnDate:(NSDate *)referenceDate; 35 | - (NSInteger) hg_age; 36 | - (NSString *) hg_fullName; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /tests/unit/allTests.m: -------------------------------------------------------------------------------- 1 | // icalBuddy all unit tests 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import "allTests.h" 31 | 32 | #import "EventsTest.h" 33 | 34 | 35 | 36 | NSArray *getAllTests() 37 | { 38 | NSMutableArray *allTests = [NSMutableArray array]; 39 | 40 | [allTests addObject:[EventsTest new]]; 41 | 42 | return allTests; 43 | } 44 | 45 | -------------------------------------------------------------------------------- /calendarStoreImport.h: -------------------------------------------------------------------------------- 1 | // icalBuddy calendar store import 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2012 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #ifdef USE_MOCKED_CALENDARSTORE 31 | #import "calendarStoreMock/MockCalCalendarStore.h" 32 | #define CALENDAR_STORE MockCalCalendarStore 33 | #else 34 | #import 35 | #define CALENDAR_STORE CalCalendarStore 36 | #endif 37 | 38 | 39 | -------------------------------------------------------------------------------- /utils/markdown/License.text: -------------------------------------------------------------------------------- 1 | Copyright (c) 2004, John Gruber 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 16 | * Neither the name "Markdown" nor the names of its contributors may 17 | be used to endorse or promote products derived from this software 18 | without specific prior written permission. 19 | 20 | This software is provided by the copyright holders and contributors "as 21 | is" and any express or implied warranties, including, but not limited 22 | to, the implied warranties of merchantability and fitness for a 23 | particular purpose are disclaimed. In no event shall the copyright owner 24 | or contributors be liable for any direct, indirect, incidental, special, 25 | exemplary, or consequential damages (including, but not limited to, 26 | procurement of substitute goods or services; loss of use, data, or 27 | profits; or business interruption) however caused and on any theory of 28 | liability, whether in contract, strict liability, or tort (including 29 | negligence or otherwise) arising in any way out of the use of this 30 | software, even if advised of the possibility of such damage. 31 | -------------------------------------------------------------------------------- /HGCLIUtils.h: -------------------------------------------------------------------------------- 1 | // CLI app utils 2 | // 3 | // http://hasseg.org/ 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2010 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import 31 | #import "HGUtils.h" 32 | 33 | 34 | extern NSStringEncoding outputStrEncoding; 35 | extern BOOL debugPrintEnabled; 36 | 37 | 38 | void Print(NSString *aStr); 39 | void Printf(NSString *aStr, ...); 40 | void PrintfErr(NSString *aStr, ...); 41 | void DebugPrintf(NSString *aStr, ...); 42 | 43 | void wordWrapMutableAttrStr(NSMutableAttributedString *mutableAttrStr, NSUInteger width); 44 | 45 | 46 | -------------------------------------------------------------------------------- /tests/unit/TestInfo.h: -------------------------------------------------------------------------------- 1 | // icalBuddy unit test info container 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import 31 | 32 | 33 | @interface TestInfo : NSObject 34 | { 35 | NSUInteger numTests; 36 | NSUInteger numSuccesses; 37 | BOOL success; 38 | NSMutableString *output; 39 | } 40 | 41 | @property() NSUInteger numTests; 42 | @property() NSUInteger numSuccesses; 43 | @property() BOOL success; 44 | @property(retain) NSMutableString *output; 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /tests/unit/TestInfo.m: -------------------------------------------------------------------------------- 1 | // icalBuddy unit test info container 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import "TestInfo.h" 31 | 32 | 33 | @implementation TestInfo 34 | 35 | @synthesize numTests; 36 | @synthesize numSuccesses; 37 | @synthesize success; 38 | @synthesize output; 39 | 40 | - (id) init 41 | { 42 | if (!(self = [super init])) 43 | return nil; 44 | 45 | self.output = [NSMutableString string]; 46 | 47 | return self; 48 | } 49 | 50 | - (void) dealloc 51 | { 52 | self.output = nil; 53 | [super dealloc]; 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /IcalBuddyAutoUpdaterDelegate.m: -------------------------------------------------------------------------------- 1 | // icalBuddy 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2012 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import "IcalBuddyAutoUpdaterDelegate.h" 31 | #import "HGCLIAutoUpdater.h" 32 | #import "HGCLIUtils.h" 33 | 34 | 35 | @implementation IcalBuddyAutoUpdaterDelegate 36 | 37 | - (id) init 38 | { 39 | if (!(self = [super initWithAppName:@"icalBuddy"])) 40 | return nil; 41 | 42 | return self; 43 | } 44 | 45 | - (void) autoUpdater:(HGCLIAutoUpdater *)autoUpdater didInstallVersion:(NSString *)latestVersionStr 46 | { 47 | Printf(@"You can run \"icalBuddy -V\" to confirm the update.\n\n"); 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /HGDateFunctions.h: -------------------------------------------------------------------------------- 1 | // Date utility functions 2 | // 3 | // http://hasseg.org/ 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2010 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import 31 | 32 | 33 | 34 | 35 | NSDate *dateForStartOfDay(NSDate *date); 36 | NSDate *dateForEndOfDay(NSDate *date); 37 | 38 | NSDate *dateByAddingDays(NSDate *date, NSInteger days); 39 | NSDate *dateByAddingMinutes(NSDate *date, NSInteger minutes); 40 | 41 | BOOL datesRepresentSameDay(NSDate *date1, NSDate *date2); 42 | 43 | NSInteger getNumWeeksInYear(NSInteger year); 44 | 45 | NSInteger getWeekDiff(NSDate *date1, NSDate *date2); 46 | NSInteger getDayDiff(NSDate *date1, NSDate *date2); 47 | 48 | NSDate *dateFromUserInput(NSString *input, NSString *inputName, BOOL endOfDay); 49 | void printDateFormatInfo(); 50 | 51 | 52 | -------------------------------------------------------------------------------- /icalBuddyArgs.h: -------------------------------------------------------------------------------- 1 | // icalBuddy arguments handling functions 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import 31 | #import "icalBuddyPrettyPrint.h" 32 | #import "icalBuddyDefines.h" 33 | 34 | 35 | void readArgsFromConfigFile(AppOptions *opts, PrettyPrintOptions *prettyPrintOptions, NSString *filePath, NSMutableDictionary **retConfigDict); 36 | 37 | void readProgramArgs(AppOptions *opts, PrettyPrintOptions *prettyPrintOptions, int argc, char *argv[]); 38 | 39 | void readConfigAndL10NFilePathArgs(int argc, char *argv[], NSString **retConfigFilePath, NSString **retL10NConfigFilePath); 40 | 41 | void processAppOptions(AppOptions *opts, PrettyPrintOptions *prettyPrintOptions, NSArray **retPropertySeparators); 42 | 43 | -------------------------------------------------------------------------------- /deployment-files/exampleLocalizationFiles/english-icalBuddyLocalization.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | title 6 | title 7 | location 8 | location 9 | notes 10 | notes 11 | url 12 | url 13 | dueDate 14 | due 15 | noDueDate 16 | no due date 17 | priority 18 | priority 19 | someonesBirthday 20 | %@'s Birthday (age %i) 21 | today 22 | today 23 | tomorrow 24 | tomorrow 25 | yesterday 26 | yesterday 27 | dayBeforeYesterday 28 | day before yesterday 29 | dayAfterTomorrow 30 | day after tomorrow 31 | xDaysAgo 32 | %d days ago 33 | xDaysFromNow 34 | %d days from now 35 | thisWeek 36 | this week 37 | lastWeek 38 | last week 39 | nextWeek 40 | next week 41 | xWeeksAgo 42 | %d weeks ago 43 | xWeeksFromNow 44 | %d weeks from now 45 | high 46 | high 47 | medium 48 | medium 49 | low 50 | low 51 | noPriority 52 | none 53 | priorityTitle 54 | %@ priority 55 | priorityTitleNone 56 | No priority 57 | dateTimeSeparator 58 | at 59 | noItems 60 | Nothing. 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /deployment-files/example-icalBuddyConfig.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | constantArguments 6 | 7 | bullet 8 | - 9 | alertBullet 10 | !! 11 | noCalendarNames 12 | 13 | formatOutput 14 | 15 | includeCals 16 | Home,Work 17 | 18 | formatting 19 | 20 | datetimeName 21 | cyan 22 | datetimeValue 23 | yellow 24 | titleValue 25 | magenta,bg:black 26 | notesName 27 | cyan 28 | notesValue 29 | white 30 | urlName 31 | cyan 32 | urlValue 33 | white 34 | locationName 35 | cyan 36 | locationValue 37 | white 38 | dueDateName 39 | cyan 40 | dueDateValue 41 | yellow 42 | priorityName 43 | cyan 44 | priorityValue 45 | black,bg:white 46 | priorityValueHigh 47 | red,bg:white 48 | priorityValueMedium 49 | yellow,bg:white 50 | priorityValueLow 51 | green,bg:white 52 | sectionTitle 53 | blue,underlined 54 | bullet 55 | white 56 | alertBullet 57 | red 58 | firstItemLine 59 | bold 60 | 61 | formattedKeywords 62 | 63 | today 64 | red,bold 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /deployment-files/exampleLocalizationFiles/japanese-icalBuddyLocalization.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | title 6 | タイトル 7 | location 8 | 場所 9 | notes 10 | メモ 11 | url 12 | URL 13 | dueDate 14 | 期日 15 | noDueDate 16 | 期日なし 17 | priority 18 | 順位 19 | someonesBirthday 20 | %@の誕生日 21 | someonesBirthdayNoAge 22 | %@の誕生日 23 | today 24 | 今日 25 | tomorrow 26 | 明日 27 | yesterday 28 | 昨日 29 | dayBeforeYesterday 30 | 一昨日 31 | dayAfterTomorrow 32 | 明後日 33 | xDaysAgo 34 | %d日前 35 | xDaysFromNow 36 | 今日から%d日 37 | thisWeek 38 | 今週 39 | lastWeek 40 | 先週 41 | nextWeek 42 | 来週 43 | xWeeksAgo 44 | %d週間前 45 | xWeeksFromNow 46 | 今日から%d週間 47 | high 48 | 高い優先度 49 | medium 50 | 中優先度 51 | low 52 | 低い優先度 53 | noPriority 54 | 優先度なし 55 | priorityTitleHigh 56 | 高い優先度 57 | priorityTitleMedium 58 | 中優先度 59 | priorityTitleLow 60 | 低い優先度 61 | priorityTitleNone 62 | 優先度なし 63 | dateTimeSeparator 64 | 65 | noItems 66 | なし 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /deployment-files/exampleLocalizationFiles/hungarian-icalBuddyLocalization.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | title 6 | cím 7 | location 8 | helyszín 9 | notes 10 | megjegyzés 11 | url 12 | url 13 | dueDate 14 | lejárat 15 | noDueDate 16 | nincs jár le 17 | priority 18 | prio 19 | someonesBirthday 20 | %@ %i. születésnapja 21 | someonesBirthdayNoAge 22 | %@ születésnapja 23 | today 24 | ma 25 | tomorrow 26 | holnap 27 | yesterday 28 | tegnap 29 | dayBeforeYesterday 30 | tegnapelőtt 31 | dayAfterTomorrow 32 | holnapután 33 | xDaysAgo 34 | %d napja 35 | xDaysFromNow 36 | %d nap múlva 37 | thisWeek 38 | e hét 39 | lastWeek 40 | múlt hét 41 | nextWeek 42 | jövő hét 43 | xWeeksAgo 44 | %d hete 45 | xWeeksFromNow 46 | %d hét múlva 47 | high 48 | magyas 49 | medium 50 | közepes 51 | low 52 | alacsony 53 | noPriority 54 | nincs 55 | priorityTitle 56 | %@ prioritás 57 | priorityTitleNone 58 | Nincs prioritás 59 | dateTimeSeparator 60 | / 61 | noItems 62 | Nincs bejegyzés. 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /deployment-files/exampleLocalizationFiles/chinese-icalBuddyLocalization.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | title 6 | 项目 7 | notes 8 | 备注 9 | url 10 | URL 11 | location 12 | 位置 13 | dueDate 14 | 截止日期 15 | noDueDate 16 | 无截止日期 17 | priority 18 | 优先级 19 | high 20 | 21 | medium 22 | 23 | low 24 | 25 | noPriority 26 | 27 | priorityTitle 28 | %@优先级 29 | priorityTitleNone 30 | 无优先级 31 | priorityTitleLow 32 | 低优先级 33 | priorityTitleMedium 34 | 中优先级 35 | priorityTitleHigh 36 | 高优先级 37 | someonesBirthday 38 | “%@” 的 %i 岁生日 39 | someonesBirthdayNoAge 40 | “%@” 岁生日 41 | today 42 | 今天 43 | tomorrow 44 | 明天 45 | yesterday 46 | 昨天 47 | dayBeforeYesterday 48 | 前天 49 | dayAfterTomorrow 50 | 后天 51 | xDaysAgo 52 | %d天前 53 | xDaysFromNow 54 | %d天后 55 | thisWeek 56 | 本周 57 | lastWeek 58 | 上周 59 | nextWeek 60 | 下周 61 | xWeeksAgo 62 | %d周前 63 | xWeeksFromNow 64 | %d周后 65 | dateTimeSeparator 66 | 67 | noItems 68 | 无项目 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /tests/unit/IcalBuddyUnitTest.h: -------------------------------------------------------------------------------- 1 | // icalBuddy-specific unit test 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import 31 | #import "UnitTest.h" 32 | 33 | #import "../../HGUtils.h" 34 | #import "../../HGCLIUtils.h" 35 | #import "../../HGCLIAutoUpdater.h" 36 | #import "../../HGDateFunctions.h" 37 | 38 | #import "../../icalBuddyDefines.h" 39 | 40 | #import "../../icalBuddyL10N.h" 41 | #import "../../icalBuddyFormatting.h" 42 | #import "../../icalBuddyPrettyPrint.h" 43 | #import "../../icalBuddyArgs.h" 44 | #import "../../icalBuddyFunctions.h" 45 | 46 | #import "../../calendarStoreImport.h" 47 | #import "../../calendarStoreMock/mockHelperFunctions.h" 48 | 49 | 50 | @interface IcalBuddyUnitTest : UnitTest 51 | { 52 | 53 | } 54 | 55 | - (AppOptions) setUpWithNowDate:(NSDate *)date opts:(NSArray *)argsArr; 56 | 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /calendarStoreMock/mockHelperFunctions.h: -------------------------------------------------------------------------------- 1 | // icalBuddy mocked CalendarStore helper functions 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import "../HGUtils.h" 31 | #import "../HGDateFunctions.h" 32 | #import 33 | #import 34 | #import 35 | #import 36 | 37 | 38 | NSDate *dateFromStr(NSString *str); 39 | 40 | CalCalendar *newCalendar(NSString *title, NSColor *color); 41 | CalEvent *newEvent(CalCalendar *calendar, 42 | NSString *title, NSString *location, 43 | NSString *start, NSString *end, 44 | NSString *notes, NSURL *url 45 | ); 46 | CalEvent *newAllDayEvent(CalCalendar *calendar, 47 | NSString *title, NSString *location, 48 | NSString *start, NSString *end, 49 | NSString *notes, NSURL *url 50 | ); 51 | 52 | 53 | -------------------------------------------------------------------------------- /deployment-files/exampleLocalizationFiles/finnish-icalBuddyLocalization.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | title 6 | otsikko 7 | location 8 | sijainti 9 | notes 10 | muistiinpanot 11 | url 12 | url 13 | dueDate 14 | eräpäivä 15 | noDueDate 16 | ei eräpäivää 17 | priority 18 | prioriteetti 19 | someonesBirthday 20 | %@:n Syntymäpäivä (%i vuotta) 21 | someonesBirthdayNoAge 22 | %@:n Syntymäpäivä 23 | today 24 | tänään 25 | tomorrow 26 | huomenna 27 | yesterday 28 | eilen 29 | dayBeforeYesterday 30 | toissapäivänä 31 | dayAfterTomorrow 32 | ylihuomenna 33 | xDaysAgo 34 | %d päivää sitten 35 | xDaysFromNow 36 | %d päivän kuluttua 37 | thisWeek 38 | tällä viikolla 39 | lastWeek 40 | viime viikolla 41 | nextWeek 42 | ensi viikolla 43 | xWeeksAgo 44 | %d viikkoa sitten 45 | xWeeksFromNow 46 | %d viikon päästä 47 | high 48 | korkea 49 | medium 50 | normaali 51 | low 52 | alhainen 53 | noPriority 54 | ei prioriteettia 55 | priorityTitle 56 | %@ prioriteetti 57 | priorityTitleNone 58 | Ei prioriteettia 59 | dateTimeSeparator 60 | klo 61 | noItems 62 | Ei mitään. 63 | 64 | 65 | -------------------------------------------------------------------------------- /icalBuddyFunctions.h: -------------------------------------------------------------------------------- 1 | // icalBuddy 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import 31 | #import "icalBuddyDefines.h" 32 | #import "icalBuddyPrettyPrint.h" 33 | 34 | // todo: the right place for these? 35 | extern NSDate *now; 36 | extern NSDate *today; 37 | 38 | 39 | BOOL areWePrintingItems(AppOptions *opts); 40 | BOOL areWePrintingEvents(AppOptions *opts); 41 | BOOL areWePrintingTasks(AppOptions *opts); 42 | BOOL areWePrintingAlsoPastEvents(AppOptions *opts); 43 | 44 | NSArray *getCalItems(AppOptions *opts); 45 | NSArray *sortCalItems(AppOptions *opts, NSArray *calItems); 46 | NSArray *putItemsUnderSections(AppOptions *opts, NSArray *calItems); 47 | 48 | CalItemPrintOption getPrintOptions(AppOptions *opts); 49 | NSArray *getCalendars(AppOptions *opts); 50 | 51 | void printAvailableStringEncodings(); 52 | void openConfigFileInEditor(NSString *configFilePath, BOOL openInCLIEditor); 53 | 54 | -------------------------------------------------------------------------------- /testRunner.m: -------------------------------------------------------------------------------- 1 | // icalBuddy test runner 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #ifndef USE_MOCKED_CALENDARSTORE 31 | #define USE_MOCKED_CALENDARSTORE 32 | #endif 33 | 34 | #import 35 | 36 | #import "tests/unit/UnitTest.h" 37 | #import "tests/unit/allTests.h" 38 | 39 | 40 | 41 | int main(int argc, char *argv[]) 42 | { 43 | NSAutoreleasePool *autoReleasePool = [[NSAutoreleasePool alloc] init]; 44 | 45 | NSUInteger totalNumTests = 0; 46 | NSUInteger totalNumSuccesses = 0; 47 | 48 | NSArray *allTests = getAllTests(); 49 | for (UnitTest *test in allTests) 50 | { 51 | TestInfo *info = [test runTests]; 52 | totalNumTests += info.numTests; 53 | totalNumSuccesses += info.numSuccesses; 54 | } 55 | 56 | Printf(@"\n"); 57 | PRINTLN_Y(@"%i/%i tests succeeded.", totalNumSuccesses, totalNumTests); 58 | 59 | [autoReleasePool release]; 60 | return(0); 61 | } 62 | -------------------------------------------------------------------------------- /deployment-files/exampleLocalizationFiles/german-icalBuddyLocalization.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | title 6 | Titel 7 | location 8 | Ort 9 | notes 10 | Notiz 11 | url 12 | URL 13 | dueDate 14 | Fällig 15 | noDueDate 16 | Kein Fälligkeitsdatum 17 | priority 18 | Priorität 19 | someonesBirthday 20 | Geburtstag %@ 21 | someonesBirthdayNoAge 22 | Geburtstag %@ 23 | today 24 | Heute 25 | tomorrow 26 | Morgen 27 | yesterday 28 | Gestern 29 | dayBeforeYesterday 30 | Vorgestern 31 | dayAfterTomorrow 32 | Übermorgen 33 | xDaysAgo 34 | vor %d Tagen 35 | xDaysFromNow 36 | in %d Tagen 37 | thisWeek 38 | Diese Woche 39 | lastWeek 40 | Letzte Woche 41 | nextWeek 42 | Nächste Woche 43 | xWeeksAgo 44 | vor %d Wochen 45 | xWeeksFromNow 46 | in %d Wochen 47 | high 48 | Hoch 49 | medium 50 | Mittel 51 | low 52 | Gering 53 | 65 | dateTimeSeparator 66 | um 67 | noItems 68 | Keine 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /deployment-files/exampleLocalizationFiles/dutch-icalBuddyLocalization.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | title 6 | Titel 7 | location 8 | Locatie 9 | notes 10 | Notities 11 | url 12 | URL 13 | dueDate 14 | Vervalt 15 | noDueDate 16 | Geen vervaldatum 17 | priority 18 | Prioriteit 19 | someonesBirthday 20 | Verjaardag van %@ 21 | someonesBirthdayNoAge 22 | Verjaardag van %@ 23 | today 24 | Vandaag 25 | tomorrow 26 | Morgen 27 | yesterday 28 | Gisteren 29 | dayBeforeYesterday 30 | Eergisteren 31 | dayAfterTomorrow 32 | Overmorgen 33 | xDaysAgo 34 | %d dagen geleden 35 | xDaysFromNow 36 | over %d dagen 37 | thisWeek 38 | deze week 39 | lastWeek 40 | vorige week 41 | nextWeek 42 | volgende week 43 | xWeeksAgo 44 | %d weken geleden 45 | xWeeksFromNow 46 | over %d weken 47 | high 48 | Hoog 49 | medium 50 | Medium 51 | low 52 | Laag 53 | 65 | dateTimeSeparator 66 | om 67 | noItems 68 | Niets 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /deployment-files/exampleLocalizationFiles/italian-icalBuddyLocalization.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | title 6 | titolo 7 | location 8 | luogo 9 | notes 10 | note 11 | url 12 | url 13 | dueDate 14 | scadenza 15 | noDueDate 16 | senza scadenza 17 | priority 18 | priorità 19 | someonesBirthday 20 | Compleanno di %@ 21 | someonesBirthdayNoAge 22 | Compleanno di %@ 23 | today 24 | oggi 25 | tomorrow 26 | domani 27 | yesterday 28 | ieri 29 | dayBeforeYesterday 30 | vantieri 31 | dayAfterTomorrow 32 | dopodomani 33 | xDaysAgo 34 | %d giorni fa 35 | xDaysFromNow 36 | %d giorni da oggi 37 | thisWeek 38 | questa settimana 39 | lastWeek 40 | scorsa settimana 41 | nextWeek 42 | prossima settimana 43 | xWeeksAgo 44 | %d settimane fa 45 | xWeeksFromNow 46 | %d settimane da questa 47 | high 48 | alta 49 | medium 50 | media 51 | low 52 | bassa 53 | 65 | dateTimeSeparator 66 | alle 67 | noItems 68 | Niente 69 | 70 | 71 | -------------------------------------------------------------------------------- /deployment-files/exampleLocalizationFiles/polish-icalBuddyLocalization.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | title 6 | tytuł 7 | location 8 | miejsce 9 | notes 10 | notatka 11 | url 12 | url 13 | dueDate 14 | planowo 15 | noDueDate 16 | bez planów czasowych 17 | priority 18 | priorytet 19 | someonesBirthday 20 | %@ ma urodziny 21 | someonesBirthdayNoAge 22 | %@ ma urodziny 23 | today 24 | dzisiaj 25 | tomorrow 26 | jutro 27 | yesterday 28 | wczoraj 29 | dayBeforeYesterday 30 | przedwczoraj 31 | dayAfterTomorrow 32 | pojutrze 33 | xDaysAgo 34 | %d dni temu 35 | xDaysFromNow 36 | %d dni od dzisiaj 37 | thisWeek 38 | w tym tygodniu 39 | lastWeek 40 | w zeszłym tygodniu 41 | nextWeek 42 | w przyszłym tygodniu 43 | xWeeksAgo 44 | %d tygodni temu 45 | xWeeksFromNow 46 | za %d tygodni 47 | high 48 | wysoki 49 | medium 50 | średni 51 | low 52 | niski 53 | 65 | dateTimeSeparator 66 | o 67 | noItems 68 | Brak 69 | 70 | 71 | -------------------------------------------------------------------------------- /deployment-files/exampleLocalizationFiles/french-icalBuddyLocalization.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | title 6 | titre 7 | location 8 | emplacement 9 | notes 10 | remarque 11 | url 12 | url 13 | dueDate 14 | échéance 15 | noDueDate 16 | aucune échéance 17 | priority 18 | priorité 19 | someonesBirthday 20 | anniversaire de %@ 21 | someonesBirthdayNoAge 22 | anniversaire de %@ 23 | today 24 | aujourd'hui 25 | tomorrow 26 | demain 27 | yesterday 28 | hier 29 | dayBeforeYesterday 30 | avant hier 31 | dayAfterTomorrow 32 | après demain 33 | xDaysAgo 34 | il y a %d jours 35 | xDaysFromNow 36 | dans %d jour 37 | thisWeek 38 | cette semaine 39 | lastWeek 40 | la semaine dernière 41 | nextWeek 42 | la semaine prochaine 43 | xWeeksAgo 44 | il y a %d semaines 45 | xWeeksFromNow 46 | dans %d semaines 47 | high 48 | haute 49 | medium 50 | moyenne 51 | low 52 | basse 53 | noPriority 54 | aucune priorité 55 | priorityTitleHigh 56 | Rang de priorité élevé 57 | priorityTitleMedium 58 | Priorité moyenne 59 | priorityTitleLow 60 | Basse priorité 61 | priorityTitleNone 62 | Aucune priorité 63 | dateTimeSeparator 64 | à 65 | noItems 66 | Vide 67 | 68 | 69 | -------------------------------------------------------------------------------- /deployment-files/exampleLocalizationFiles/latin-icalBuddyLocalization.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | title 6 | titulus 7 | location 8 | locus 9 | notes 10 | hypomnemata 11 | url 12 | nexus interretialis 13 | dueDate 14 | debitur 15 | noDueDate 16 | debitur quolibet die 17 | priority 18 | momenti 19 | someonesBirthday 20 | %@ hodie suum diem natalem celebrat 21 | someonesBirthdayNoAge 22 | %@ hodie suum diem natalem celebrat 23 | today 24 | hodie 25 | tomorrow 26 | cras 27 | yesterday 28 | heri 29 | dayBeforeYesterday 30 | nudiustertius 31 | dayAfterTomorrow 32 | perendie 33 | xDaysAgo 34 | abhinc dies %d 35 | xDaysFromNow 36 | post dies %d 37 | thisWeek 38 | hac hebdomade 39 | lastWeek 40 | praeterita hebdomade 41 | nextWeek 42 | proxima hebdomade 43 | xWeeksAgo 44 | abhinc hebdomades %d 45 | xWeeksFromNow 46 | post habedomades %d 47 | high 48 | magni 49 | medium 50 | alicuius 51 | low 52 | parvi 53 | 65 | dateTimeSeparator 66 | 67 | noItems 68 | Nihil 69 | 70 | 71 | -------------------------------------------------------------------------------- /todo.markdown: -------------------------------------------------------------------------------- 1 | 2 | TODO: 3 | 4 | before next release: 5 | ------------------------- 6 | - update translations for new priority L10N strings 7 | - Need people to help me with this. 8 | 9 | 10 | own ideas: 11 | ------------------------- 12 | - allow user to put config files under ~/.icalBuddy/. 13 | 14 | - preference for specifying short/medium/long/full date/time formats? 15 | 16 | - simplify handling of "relative dates" -- there's a special case (with the 17 | -nrd argument and all) and there's the %RD specifier. if we need both, their 18 | coexistence should be clearer. 19 | 20 | 21 | user requests: 22 | ------------------------- 23 | - Output both events and tasks into the same list 24 | - Problem: how to handle args that assume we're printing only events or tasks? 25 | 26 | - ability to specify color for specific calendars not just specific words (user 27 | ref: Edward) 28 | 29 | - Add argument -co (or: --calendarOrder) (user ref: Derek) 30 | 31 | - ability to only get tasks with specific priorities 32 | - ability to only get only undated tasks (or no undated tasks) (user ref: Thomas R.) 33 | - Add argument for seeing only recurring events (user ref: Jonathan) 34 | - Add support for date suffixes (e.g. 1st, 2nd...) (user ref: Sam) 35 | - ability to use relative dates today and tomorrow but the rest as normal 36 | dates... I don't like the long "day after tomorrow" text it seems to defeat 37 | the purpose of the simple today and tomorrow scheme (user ref: Edward) 38 | - Display also attachments 39 | - Display also attendees 40 | - AddressBookBuddy (user ref: Paul E.) 41 | 42 | 43 | other (my own ideas): 44 | ------------------------- 45 | 46 | - Write better examples to the web page in order to better illustrate the 47 | customizability of output formatting 48 | - Implement wrapping to a specified number of maximum characters on each line 49 | (problem: will look off with non-fixed-width fonts if we try to match 50 | indenting levels and fixing those problems with arguments might become really 51 | complex (i.e. you would need too many different kinds of arguments for all 52 | the different cases)) 53 | 54 | - Think about timezone support (how to handle these? what kind of support would 55 | we need? the "eventsFrom: to:" command already requires the timezone to be 56 | specified.) 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /deployment-files/exampleLocalizationFiles/spanish-icalBuddyLocalization.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | title 6 | titulo 7 | location 8 | locación 9 | notes 10 | notas 11 | url 12 | url 13 | dueDate 14 | hacer 15 | noDueDate 16 | no tiene fecha para terminar 17 | priority 18 | prioridad 19 | someonesBirthday 20 | Cumpleaños de %@ 21 | someonesBirthdayNoAge 22 | Cumpleaños de %@ 23 | today 24 | hoy 25 | tomorrow 26 | mañana 27 | yesterday 28 | ayer 29 | dayBeforeYesterday 30 | ante ayer 31 | dayAfterTomorrow 32 | pasado mañana 33 | xDaysAgo 34 | hace %d días 35 | xDaysFromNow 36 | %d dias a partir de hoy 37 | thisWeek 38 | esta semana 39 | lastWeek 40 | la semana pasada 41 | nextWeek 42 | la proxima semana 43 | xWeeksAgo 44 | %d semanas atras 45 | xWeeksFromNow 46 | %d semanas a partir de hoy 47 | high 48 | alta 49 | medium 50 | media 51 | low 52 | baja 53 | noPriority 54 | no es una prioridad 55 | priorityTitleHigh 56 | Alta prioridad 57 | priorityTitleMedium 58 | Prioridad media 59 | priorityTitleLow 60 | De baja prioridad 61 | priorityTitleNone 62 | No es una prioridad 63 | dateTimeSeparator 64 | a las 65 | noItems 66 | Nada. 67 | 68 | 69 | -------------------------------------------------------------------------------- /icalBuddyFormatting.h: -------------------------------------------------------------------------------- 1 | // icalBuddy output formatting functions 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import 31 | #import 32 | #import 33 | 34 | void initFormatting(NSDictionary *aFormattingConfigDict, NSArray *aPropertySeparators); 35 | 36 | NSColor *getClosestAnsiColorForColor(NSColor *color, BOOL foreground); 37 | 38 | NSMutableDictionary* formattingConfigToStringAttributes(NSString *formattingConfig, CalCalendarItem *calItem); 39 | 40 | void processCustomStringAttributes(NSMutableAttributedString **aAttributedString); 41 | 42 | NSDictionary* getStringAttributesForKey(NSString *key, CalCalendarItem *calItem); 43 | 44 | NSDictionary* getSectionTitleStringAttributes(NSString *sectionTitle); 45 | NSDictionary* getFirstLineStringAttributes(CalCalendarItem *calItem); 46 | NSDictionary* getBulletStringAttributes(BOOL isAlertBullet, CalCalendarItem *calItem); 47 | NSDictionary* getCalNameInTitleStringAttributes(CalCalendarItem *calItem); 48 | NSDictionary* getPropNameStringAttributes(NSString *propName, CalCalendarItem *calItem); 49 | NSDictionary* getPropValueStringAttributes(NSString *propName, NSString *propValue, CalCalendarItem *calItem); 50 | 51 | NSString* getPropSeparatorStr(NSUInteger propertyNumber); 52 | 53 | NSString *ansiEscapedStringWithAttributedString(NSAttributedString *str); 54 | 55 | -------------------------------------------------------------------------------- /tests/regression/ansihelper.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def wrap_ansi(s, start_code, end_code): 4 | return '\x1b[%im%s\x1b[%im' % (start_code, s, end_code) 5 | 6 | 7 | def wrap_ansi_sgr(s, sgr): 8 | sgr_by_ten = int(sgr / 10.0) 9 | end_code = 49 if (sgr_by_ten == 4 or sgr_by_ten == 10) else 39 10 | return wrap_ansi(s, sgr, end_code) 11 | 12 | 13 | def black(s): 14 | return wrap_ansi_sgr(s, 30) 15 | 16 | 17 | def bright_black(s): 18 | return wrap_ansi_sgr(s, 90) 19 | 20 | 21 | def red(s): 22 | return wrap_ansi_sgr(s, 31) 23 | 24 | 25 | def green(s): 26 | return wrap_ansi_sgr(s, 32) 27 | 28 | 29 | def yellow(s): 30 | return wrap_ansi_sgr(s, 33) 31 | 32 | 33 | def blue(s): 34 | return wrap_ansi_sgr(s, 34) 35 | 36 | 37 | def magenta(s): 38 | return wrap_ansi_sgr(s, 35) 39 | 40 | 41 | def cyan(s): 42 | return wrap_ansi_sgr(s, 36) 43 | 44 | 45 | def white(s): 46 | return wrap_ansi_sgr(s, 37) 47 | 48 | 49 | def bg_black(s): 50 | return wrap_ansi_sgr(s, 40) 51 | 52 | 53 | def bg_bright_black(s): 54 | return wrap_ansi_sgr(s, 100) 55 | 56 | 57 | def bg_red(s): 58 | return wrap_ansi_sgr(s, 41) 59 | 60 | 61 | def bg_green(s): 62 | return wrap_ansi_sgr(s, 42) 63 | 64 | 65 | def bg_yellow(s): 66 | return wrap_ansi_sgr(s, 43) 67 | 68 | 69 | def bg_blue(s): 70 | return wrap_ansi_sgr(s, 44) 71 | 72 | 73 | def bg_magenta(s): 74 | return wrap_ansi_sgr(s, 45) 75 | 76 | 77 | def bg_cyan(s): 78 | return wrap_ansi_sgr(s, 46) 79 | 80 | 81 | def bg_white(s): 82 | return wrap_ansi_sgr(s, 47) 83 | 84 | 85 | def bold(s): 86 | return wrap_ansi(s, 1, 22) 87 | 88 | 89 | def under(s): 90 | return wrap_ansi(s, 4, 24) 91 | 92 | 93 | # get visible length of string that has ansi escape sequences 94 | def ansi_str_len(s): 95 | s = unicode(s) 96 | clean_s = '' 97 | esc = '\x1b' 98 | len_s = len(s) 99 | last = 0 100 | i = 0 101 | while i < len_s: 102 | if s[i] == esc and (i + 1 < len_s) and s[i + 1] == '[': 103 | clean_s += s[last:i] 104 | i += 2 105 | while True: 106 | if i < len_s: 107 | i += 1 108 | ord_val = ord(s[i]) 109 | if 64 < ord_val and ord_val < 126: 110 | i += 1 111 | break 112 | last = i 113 | continue 114 | i += 1 115 | clean_s += s[last:i] 116 | return len(clean_s) 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /HGUtils.h: -------------------------------------------------------------------------------- 1 | // Misc utility functions 2 | // 3 | // http://hasseg.org/ 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2010 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import 31 | 32 | #define kHGInternalErrorDomain @"org.hasseg" 33 | 34 | // helper function macros 35 | #define kEmptyMutableAttributedString [[[NSMutableAttributedString alloc] init] autorelease] 36 | #define ATTR_STR(x) [[[NSAttributedString alloc] initWithString:(x)] autorelease] 37 | #define M_ATTR_STR(x) [[[NSMutableAttributedString alloc] initWithString:(x)] autorelease] 38 | #define WHITESPACE(x) [@"" stringByPaddingToLength:(x) withString:@" " startingAtIndex:0] 39 | 40 | NSError *hgInternalError(NSInteger code, NSString *description); 41 | 42 | NSString *strConcat(NSString *firstStr, ...); 43 | 44 | NSString *escapeDoubleQuotes(NSString *str); 45 | NSString *translateEscapeSequences(NSString *str); 46 | 47 | void replaceInMutableAttrStr(NSMutableAttributedString *str, NSString *searchStr, NSAttributedString *replaceStr); 48 | NSMutableAttributedString *mutableAttrStrWithAttrs(NSString *string, NSDictionary *attrs); 49 | 50 | NSSet *setFromCommaSeparatedStringTrimmingWhitespace(NSString *str); 51 | NSArray *arrayFromCommaSeparatedStringTrimmingWhitespace(NSString *str); 52 | NSArray *arrayFromArbitrarilySeparatedString(NSString *str, BOOL aTranslateEscapeSequences, NSError **error); 53 | 54 | NSUInteger countOccurrences(NSString *haystack, NSString *needle, NSStringCompareOptions options); 55 | 56 | BOOL moveFileToTrash(NSString *filePath); 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | 2 | SCP_TARGET=$(shell cat ../deploymentScpTarget) 3 | 4 | 5 | COMPILER_GCC="gcc" 6 | COMPILER_CLANG="/Developer/usr/bin/clang" 7 | COMPILER=$(COMPILER_CLANG) 8 | 9 | 10 | all: examples 11 | 12 | #------------------------------------------------------------------------- 13 | #------------------------------------------------------------------------- 14 | # compile tool for generating HTML from command output 15 | #------------------------------------------------------------------------- 16 | cmdStdoutToHTML: cmdStdoutToHTML.m 17 | @echo 18 | @echo ---- Compiling cmdStdoutToHTML: 19 | @echo ====================================== 20 | $(COMPILER) -Wall -std=c99 -arch i386 -framework Cocoa -o $@ cmdStdoutToHTML.m ../ANSIEscapeHelper.m ../HGCLIUtils.m ../HGUtils.m 21 | 22 | 23 | FontList.swf: FontList.as 24 | @echo 25 | @echo ---- Compiling FontList.swf: 26 | @echo ====================================== 27 | $(FLEX_HOME)/bin/mxmlc -strict=true FontList.as 28 | 29 | 30 | #------------------------------------------------------------------------- 31 | #------------------------------------------------------------------------- 32 | # generate usage examples HTML 33 | #------------------------------------------------------------------------- 34 | examples.html: cmdStdoutToHTML FontList.swf examples.markdown examples.css configExample.png generateExamplesHTML.py exampleCommandOutputs.plist 35 | @echo 36 | @echo ---- Running examples HTML generator: 37 | @echo ====================================== 38 | ./generateExamplesHTML.py > examples.html 39 | 40 | examples: examples.html 41 | 42 | 43 | 44 | exampleCommandOutputs.plist: generateExamplesOutput.py 45 | @echo 46 | @echo ---- Running example command output generator: 47 | @echo ====================================== 48 | ./generateExamplesOutput.py 49 | 50 | 51 | 52 | #------------------------------------------------------------------------- 53 | #------------------------------------------------------------------------- 54 | # deploy to server 55 | #------------------------------------------------------------------------- 56 | deploy-examples: examples 57 | @echo 58 | @echo ---- Deploying examples to server: 59 | @echo ====================================== 60 | scp -r examples.html arrow-down.png arrow-right.png configExample.png FontList.swf $(SCP_TARGET) 61 | 62 | 63 | 64 | #------------------------------------------------------------------------- 65 | #------------------------------------------------------------------------- 66 | clean: 67 | @echo 68 | @echo ---- Cleaning up: 69 | @echo ====================================== 70 | -rm -Rf examples.html 71 | -rm -Rf cmdStdoutToHTML 72 | -rm -Rf cmdStdoutToPNG 73 | -rm -Rf FontList.swf 74 | 75 | 76 | -------------------------------------------------------------------------------- /tests/unit/EventsTest.m: -------------------------------------------------------------------------------- 1 | // icalBuddy events test 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import "EventsTest.h" 31 | 32 | @implementation EventsTest 33 | 34 | - (void) setUp 35 | { 36 | CalCalendar *homeCal = newCalendar(@"Home", [NSColor greenColor]); 37 | CalCalendar *workCal = newCalendar(@"Work", [NSColor blueColor]); 38 | [CALENDAR_STORE defaultCalendarStore].calendarsArr = [NSMutableArray arrayWithObjects: 39 | homeCal, workCal, 40 | nil 41 | ]; 42 | 43 | [CALENDAR_STORE defaultCalendarStore].itemsArr = [NSMutableArray arrayWithObjects: 44 | newAllDayEvent(homeCal, @"Off from work", nil, @"2010-10-22", @"2010-10-23", nil, nil), 45 | newEvent(homeCal, @"Feed the cat", @"apartment", @"2010-10-21 15", @"2010-10-21 15", nil, nil), 46 | newEvent(homeCal, @"Watch the game", @"apartment", @"2010-10-22 16", @"2010-10-22 17", nil, nil), 47 | nil 48 | ]; 49 | } 50 | 51 | - (HG_TEST_RETURN_TYPE) testEventsNow 52 | { 53 | AppOptions opts = [self 54 | setUpWithNowDate:DATE(@"2010-10-22 16:30:00 +0200") 55 | opts:ARR(@"-sd", @"eventsNow") 56 | ]; 57 | 58 | NSArray *items = getCalItems(&opts); 59 | 60 | HG_ASSERT_EQUALS([items count], 2); 61 | HG_ASSERT_OBJ_EQUALS([[items objectAtIndex:0] title], @"Off from work"); 62 | HG_ASSERT_OBJ_EQUALS([[items objectAtIndex:1] title], @"Watch the game"); 63 | 64 | HG_TEST_DONE; 65 | } 66 | 67 | - (void) tearDown 68 | { 69 | [CALENDAR_STORE defaultCalendarStore].calendarsArr = nil; 70 | [CALENDAR_STORE defaultCalendarStore].itemsArr = nil; 71 | } 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /examples/cmdStdoutToPNG.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #import 5 | #import "ANSIEscapeHelper.h" 6 | #import "HGCLIUtils.h" 7 | #import "RegexKitLite.h" 8 | 9 | NSString *runTask(NSString *path, NSArray *args) 10 | { 11 | NSPipe *pipe; 12 | pipe = [NSPipe pipe]; 13 | 14 | NSTask *task; 15 | task = [[NSTask alloc] init]; 16 | [task setLaunchPath: path]; 17 | [task setArguments: args]; 18 | [task setStandardOutput: pipe]; 19 | 20 | NSFileHandle *file; 21 | file = [pipe fileHandleForReading]; 22 | 23 | [task launch]; 24 | 25 | NSData *data; 26 | data = [file readDataToEndOfFile]; 27 | 28 | NSString *string; 29 | string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]; 30 | 31 | [task release]; 32 | 33 | return [string autorelease]; 34 | } 35 | 36 | 37 | 38 | 39 | #define VIEW_SIZE NSMakeRect(0,0, 500, 400) 40 | #define FONT_NAME @"Monaco" 41 | #define FONT_SIZE 9 42 | #define TEXT_COLOR [NSColor whiteColor] 43 | #define BACKGROUND_COLOR [NSColor blackColor] 44 | 45 | int main(int argc, char *argv[]) 46 | { 47 | NSAutoreleasePool *autoReleasePool = [[NSAutoreleasePool alloc] init]; 48 | 49 | if (argc == 1) 50 | { 51 | Print(@"Need command to run as an argument.\n"); 52 | return 1; 53 | } 54 | 55 | NSString *command = [NSString stringWithUTF8String:argv[1]]; 56 | 57 | command = [command stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 58 | if ([command length] == 0) 59 | { 60 | Print(@"Need command to run as an argument.\n"); 61 | return 1; 62 | } 63 | 64 | ANSIEscapeHelper *ansiHelper = [[[ANSIEscapeHelper alloc] init] autorelease]; 65 | ansiHelper.defaultStringColor = TEXT_COLOR; 66 | 67 | NSTextView *textView = [[[NSTextView alloc] initWithFrame:VIEW_SIZE] autorelease]; 68 | [textView setEditable:NO]; 69 | [textView setBackgroundColor:BACKGROUND_COLOR]; 70 | 71 | NSString *output = runTask(@"/bin/bash", [NSArray arrayWithObjects: @"-c", command, nil]); 72 | 73 | NSAttributedString *attrStr = [ansiHelper attributedStringWithANSIEscapedString:output]; 74 | [[textView textStorage] setAttributedString:attrStr]; 75 | [[textView textStorage] setFont:[NSFont fontWithName:FONT_NAME size:FONT_SIZE]]; 76 | 77 | NSBitmapImageRep *textViewImageRep = [textView bitmapImageRepForCachingDisplayInRect:[textView frame]]; 78 | [textView cacheDisplayInRect:[textView frame] toBitmapImageRep:textViewImageRep]; 79 | NSData *imagePNGData = [textViewImageRep representationUsingType:NSPNGFileType properties:nil]; 80 | 81 | [imagePNGData writeToFile:@"cmdStdout.png" atomically:YES]; 82 | 83 | 84 | [autoReleasePool release]; 85 | return 0; 86 | } 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /deployment-files/readme.txt: -------------------------------------------------------------------------------- 1 | 2 | DESCRIPTION: 3 | -------------------------------- 4 | 5 | icalBuddy is a command-line utility that can be used to query the OS X 6 | calendar database for items. It requires Mac OS 10.5 or later. 7 | 8 | Copyright 2008-2011 Ali Rantakari 9 | http://hasseg.org/icalBuddy 10 | 11 | 12 | 13 | INSTALLATION: 14 | -------------------------------- 15 | 16 | To install, just double-click on the "install.command" file in Finder (it might 17 | just say "install" if your Finder preferences are set to hide file extensions.) 18 | 19 | This script will then be run in Terminal and it will first display you the 20 | locations where icalBuddy will be installed to and then prompt you to continue. 21 | 22 | 23 | 24 | 25 | HELP / GETTING STARTED: 26 | -------------------------------- 27 | 28 | After installation you can: 29 | 30 | * Read the FAQ by opening the "faq.html" file in your web browser. 31 | 32 | * Run "man icalBuddy" in the terminal to read the program's manual page. 33 | Here you'll find documentation for all of the arguments you can use 34 | when calling icalBuddy. 35 | 36 | * Run "man icalBuddyConfig" in the terminal to read the manual page 37 | for the configuration file format. Here you'll find documentation 38 | for everything you can do with the configuration file in order 39 | to make icalBuddy always behave in the way you want. 40 | 41 | * Copy one of the included example localization files to 42 | ~/.icalBuddyLocalization.plist in order to start using them. This 43 | is only if you're interested in making icalBuddy output in a 44 | language other than english. 45 | 46 | * Run "man icalBuddyLocalization" in the terminal to read the localization 47 | manual page. This is if you're interested in writing your own 48 | localization(s). 49 | 50 | All of the three icalBuddy manual pages are also available as PDFs 51 | for your viewing pleasure. 52 | 53 | 54 | 55 | 56 | LICENSE: 57 | -------------------------------- 58 | 59 | The MIT License 60 | 61 | Copyright (c) 2008-2011 Ali Rantakari 62 | 63 | Permission is hereby granted, free of charge, to any person obtaining a copy 64 | of this software and associated documentation files (the "Software"), to deal 65 | in the Software without restriction, including without limitation the rights 66 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 67 | copies of the Software, and to permit persons to whom the Software is 68 | furnished to do so, subject to the following conditions: 69 | 70 | The above copyright notice and this permission notice shall be included in 71 | all copies or substantial portions of the Software. 72 | 73 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 74 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 75 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 76 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 77 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 78 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 79 | THE SOFTWARE. 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /HGCLIAutoUpdaterDelegate.m: -------------------------------------------------------------------------------- 1 | // CLI app auto-update code 2 | // 3 | // http://hasseg.org/ 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2010 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import "HGCLIAutoUpdaterDelegate.h" 31 | #import "HGCLIAutoUpdater.h" 32 | #import "HGCLIUtils.h" 33 | 34 | 35 | #define kAppSiteURLPrefixFormat @"http://hasseg.org/%@/" 36 | 37 | 38 | @implementation HGCLIAutoUpdaterDelegate 39 | 40 | - (id) initWithAppName:(NSString *)aAppName 41 | { 42 | if (!(self = [super init])) 43 | return nil; 44 | 45 | appName = [aAppName copy]; 46 | 47 | return self; 48 | } 49 | 50 | - (void) dealloc 51 | { 52 | [appName release], appName = nil; 53 | [super dealloc]; 54 | } 55 | 56 | 57 | 58 | - (NSString *) appSiteURLPrefix 59 | { 60 | return [NSString stringWithFormat:kAppSiteURLPrefixFormat, appName]; 61 | } 62 | 63 | 64 | - (NSURL *) latestVersionCheckURLWithCurrentVersion:(NSString *)currentVersionStr 65 | { 66 | return [NSURL URLWithString:strConcat([self appSiteURLPrefix], @"?versioncheck=y", nil)]; 67 | } 68 | 69 | - (NSURL *) latestVersionInfoWebURLWithCurrentVersion:(NSString *)currentVersionStr latestVersion:(NSString *)latestVersionStr 70 | { 71 | return [NSURL URLWithString:strConcat([self appSiteURLPrefix], @"?currentversion=", currentVersionStr, nil)]; 72 | } 73 | 74 | - (NSURL *) releaseNotesHTMLURLWithCurrentVersion:(NSString *)currentVersionStr latestVersion:(NSString *)latestVersionStr 75 | { 76 | return [NSURL URLWithString:strConcat([self appSiteURLPrefix], @"?whatschanged=y¤tversion=", currentVersionStr, nil)]; 77 | } 78 | 79 | - (NSURL *) latestVersionZIPURLWithCurrentVersion:(NSString *)currentVersionStr latestVersion:(NSString *)latestVersionStr 80 | { 81 | NSString *urlStr = strConcat( 82 | [self appSiteURLPrefix], 83 | [NSString stringWithFormat:@"%@/%@-v%@.zip", latestVersionStr, appName, latestVersionStr], 84 | nil 85 | ); 86 | return [NSURL URLWithString:urlStr]; 87 | } 88 | 89 | - (NSString *) commandToRunInstaller 90 | { 91 | return @"./install.command -y"; 92 | } 93 | 94 | 95 | @end 96 | 97 | -------------------------------------------------------------------------------- /calendarStoreMock/mockHelperFunctions.m: -------------------------------------------------------------------------------- 1 | // icalBuddy mocked CalendarStore helper functions 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import "mockHelperFunctions.h" 31 | 32 | 33 | NSDate *dateFromStr(NSString *str) 34 | { 35 | NSString *dateStr = nil; 36 | if ([str length] == 25) 37 | dateStr = str; 38 | else if ([str length] == 19) 39 | dateStr = strConcat(str, @" +0200", nil); 40 | else if ([str length] == 16) 41 | dateStr = strConcat(str, @":00 +0200", nil); 42 | else if ([str length] == 13) 43 | dateStr = strConcat(str, @":00:00 +0200", nil); 44 | else if ([str length] == 10) 45 | dateStr = strConcat(str, @" 12:00:00 +0200", nil); 46 | return [NSDate dateWithString:dateStr]; 47 | } 48 | 49 | CalCalendar *newCalendar(NSString *title, NSColor *color) 50 | { 51 | CalCalendar *cal = [CalCalendar calendar]; 52 | cal.title = title; 53 | cal.color = color; 54 | return cal; 55 | } 56 | 57 | CalEvent *newEvent(CalCalendar *calendar, 58 | NSString *title, NSString *location, 59 | NSString *start, NSString *end, 60 | NSString *notes, NSURL *url 61 | ) 62 | { 63 | CalEvent *event = [CalEvent event]; 64 | event.calendar = calendar; 65 | event.title = title; 66 | event.location = location; 67 | event.isAllDay = NO; 68 | event.startDate = dateFromStr(start); 69 | event.endDate = dateFromStr(end); 70 | event.notes = notes; 71 | event.url = url; 72 | return event; 73 | } 74 | 75 | CalEvent *newAllDayEvent(CalCalendar *calendar, 76 | NSString *title, NSString *location, 77 | NSString *start, NSString *end, 78 | NSString *notes, NSURL *url 79 | ) 80 | { 81 | CalEvent *event = [CalEvent event]; 82 | event.calendar = calendar; 83 | event.title = title; 84 | event.location = location; 85 | event.isAllDay = YES; 86 | event.startDate = dateFromStr(start); 87 | event.endDate = dateByAddingDays(dateFromStr(end), 1); 88 | event.notes = notes; 89 | event.url = url; 90 | return event; 91 | } 92 | 93 | 94 | -------------------------------------------------------------------------------- /examples/generateExamplesOutput.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import types 6 | import plistlib 7 | import codecs 8 | from subprocess import Popen, PIPE, STDOUT 9 | 10 | 11 | def runInShell(cmd): 12 | o = os.popen(cmd, 'r') 13 | return o.read() 14 | 15 | def getFileContents(path): 16 | f = open(path,'r') 17 | s = f.read().strip("\n").strip() 18 | f.close() 19 | return s 20 | 21 | 22 | commandOutputsPlistPath = 'exampleCommandOutputs.plist' 23 | configFilePath = 'exampleConfig.plist' 24 | 25 | constArgs = { 26 | 'includeCals': 'ExampleCal-Birthdays, ExampleCal-Home, ExampleCal-Work' 27 | } 28 | 29 | def createConfigFile(formattingAttrs): 30 | header = """ 31 | 32 | 33 | 34 | constantArguments 35 | 36 | """ 37 | middle = """ 38 | 39 | formatting 40 | 41 | """ 42 | footer = """ 43 | 44 | 45 | """ 46 | contents = header 47 | 48 | if constArgs != None: 49 | for key, value in constArgs.items(): 50 | contents += ''+key+'\n' 51 | if type(value) is types.StringType: 52 | contents += ''+value+'\n' 53 | elif type(value) is types.BooleanType: 54 | contents += ''+('true' if value else 'false')+'\n' 55 | 56 | contents += middle 57 | 58 | if formattingAttrs != None: 59 | for key, value in formattingAttrs.items(): 60 | contents += ''+key+'\n' 61 | contents += ''+value+'\n' 62 | 63 | contents += footer 64 | f = open(configFilePath, 'w') 65 | f.write(contents) 66 | f.close() 67 | 68 | def createEmptyConfigFile(): 69 | createConfigFile(None) 70 | 71 | 72 | md = getFileContents('examples.markdown') 73 | lines = md.splitlines(True) 74 | 75 | formatMarker = '••f' 76 | cmdMarker = '•••' 77 | 78 | commands = {} 79 | formattingDict = None 80 | 81 | if not os.path.exists(configFilePath): 82 | createEmptyConfigFile() 83 | 84 | for line in lines: 85 | if line.strip().startswith(cmdMarker): 86 | cmd = line.strip()[len(cmdMarker):].strip() 87 | if cmd.startswith('icalBuddy'): 88 | cmd = cmd.replace('icalBuddy', '/usr/local/bin/icalBuddy') 89 | 90 | cmdToRun = cmd.replace('/icalBuddy', '/icalBuddy -cf "'+configFilePath+'"') 91 | #cmdToRun = cmdToRun.replace('\\', '\\\\') 92 | #cmdToRun = cmdToRun.replace('"', '\\"') 93 | 94 | if (formattingDict != None): 95 | createConfigFile(formattingDict) 96 | 97 | p = Popen(['./cmdStdoutToHTML', '-c', cmdToRun], stdout=PIPE, stderr=PIPE) 98 | p_out, p_err = p.communicate() 99 | commands[unicode(cmd, 'utf-8')] = unicode(p_out, 'utf-8') 100 | 101 | if (formattingDict != None): 102 | createEmptyConfigFile() 103 | formattingDict = None 104 | 105 | continue 106 | elif line.strip().startswith(formatMarker): 107 | if (formattingDict == None): formattingDict = {} 108 | formatSpec = line.strip()[len(formatMarker):].split('=') 109 | formattingDict[formatSpec[0].strip()] = formatSpec[1].strip() 110 | continue 111 | 112 | plistlib.writePlist(commands, commandOutputsPlistPath) 113 | 114 | if os.path.exists(configFilePath): 115 | os.remove(configFilePath) 116 | 117 | 118 | -------------------------------------------------------------------------------- /icalBuddyL10N.h: -------------------------------------------------------------------------------- 1 | // icalBuddy localization functions 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | 31 | // localization configuration keys 32 | #define kL10nKeyPropNameTitle kPropName_title 33 | #define kL10nKeyPropNameLocation kPropName_location 34 | #define kL10nKeyPropNameNotes kPropName_notes 35 | #define kL10nKeyPropNameUrl kPropName_url 36 | #define kL10nKeyPropNamePriority kPropName_priority 37 | #define kL10nKeyPropNameUID kPropName_UID 38 | #define kL10nKeyPropNameAttendees kPropName_attendees 39 | #define kL10nKeyPropNameDueDate @"dueDate" 40 | #define kL10nKeyNoDueDate @"noDueDate" 41 | #define kL10nKeyToday @"today" 42 | #define kL10nKeyTomorrow @"tomorrow" 43 | #define kL10nKeyDayAfterTomorrow @"dayAfterTomorrow" 44 | #define kL10nKeyYesterday @"yesterday" 45 | #define kL10nKeyDayBeforeYesterday @"dayBeforeYesterday" 46 | #define kL10nKeyXDaysAgo @"xDaysAgo" 47 | #define kL10nKeyXDaysFromNow @"xDaysFromNow" 48 | #define kL10nKeyLastWeek @"lastWeek" 49 | #define kL10nKeyThisWeek @"thisWeek" 50 | #define kL10nKeyNextWeek @"nextWeek" 51 | #define kL10nKeyXWeeksAgo @"xWeeksAgo" 52 | #define kL10nKeyXWeeksFromNow @"xWeeksFromNow" 53 | #define kL10nKeyPriorityHigh @"high" 54 | #define kL10nKeyPriorityMedium @"medium" 55 | #define kL10nKeyPriorityLow @"low" 56 | #define kL10nKeyPriorityNone @"noPriority" 57 | #define kL10nKeyPriorityTitle @"priorityTitle" 58 | #define kL10nKeyPriorityTitleNone @"priorityTitleNone" 59 | #define kL10nKeyPriorityTitleLow @"priorityTitleLow" 60 | #define kL10nKeyPriorityTitleMedium @"priorityTitleMedium" 61 | #define kL10nKeyPriorityTitleHigh @"priorityTitleHigh" 62 | #define kL10nKeySomeonesBirthday @"someonesBirthday" 63 | #define kL10nKeySomeonesBirthdayNoAge @"someonesBirthdayNoAge" 64 | #define kL10nKeyMyBirthday @"myBirthday" 65 | #define kL10nKeyDateTimeSeparator @"dateTimeSeparator" 66 | #define kL10nKeyNoItemsInSection @"noItems" 67 | 68 | // localization configuration file path 69 | #define kL10nFilePath @"~/.icalBuddyLocalization.plist" 70 | 71 | void initL10N(NSString *configFilePath); 72 | void readAndValidateL10NConfigFile(NSString *filePath); 73 | 74 | NSString* localizedStr(NSString *str); 75 | 76 | -------------------------------------------------------------------------------- /ABRecord+HGAdditions.m: -------------------------------------------------------------------------------- 1 | // ABRecord+HGAdditions.m 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import "ABRecord+HGAdditions.h" 31 | 32 | @implementation ABRecord (HGAdditions) 33 | 34 | - (NSInteger) hg_ageOnDate:(NSDate *)referenceDate 35 | { 36 | NSDate *birthday = [self valueForProperty:kABBirthdayProperty]; 37 | if (birthday == nil) 38 | return NSNotFound; 39 | 40 | NSCalendar *calendar = [NSCalendar currentCalendar]; 41 | unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit; 42 | NSDateComponents *dateComponentsRefDate = [calendar components:unitFlags fromDate:referenceDate]; 43 | NSDateComponents *dateComponentsBirth = [calendar components:unitFlags fromDate:birthday]; 44 | 45 | if (([dateComponentsRefDate month] < [dateComponentsBirth month]) 46 | || (([dateComponentsRefDate month] == [dateComponentsBirth month]) 47 | && ([dateComponentsRefDate day] < [dateComponentsBirth day]))) 48 | return [dateComponentsRefDate year] - [dateComponentsBirth year] - 1; 49 | else 50 | return [dateComponentsRefDate year] - [dateComponentsBirth year]; 51 | } 52 | 53 | - (NSInteger) hg_age 54 | { 55 | return [self hg_ageOnDate:[NSDate date]]; 56 | } 57 | 58 | - (NSString *) hg_fullName 59 | { 60 | NSString *firstName = [self valueForProperty:kABFirstNameProperty]; 61 | NSString *lastName = [self valueForProperty:kABLastNameProperty]; 62 | NSString *orgName = [self valueForProperty:kABOrganizationProperty]; 63 | 64 | NSInteger personFlags = [[self valueForProperty:kABPersonFlags] integerValue]; 65 | //BOOL isPerson = (personFlags & kABShowAsMask) == kABShowAsPerson; 66 | BOOL isCompany = (personFlags & kABShowAsMask) == kABShowAsCompany; 67 | 68 | if (isCompany) 69 | return orgName; 70 | 71 | if (0 < firstName.length && 0 < lastName.length) 72 | { 73 | // Remember, -sharedAddressBook might return nil 74 | if ([[ABAddressBook sharedAddressBook] defaultNameOrdering] != kABFirstNameFirst) 75 | return [NSString stringWithFormat:@"%@ %@", lastName, firstName]; 76 | else 77 | return [NSString stringWithFormat:@"%@ %@", firstName, lastName]; 78 | } 79 | else if (0 < firstName.length) 80 | return firstName; 81 | else if (0 < lastName.length) 82 | return lastName; 83 | 84 | return nil; 85 | } 86 | 87 | @end 88 | -------------------------------------------------------------------------------- /tests/unit/IcalBuddyUnitTest.m: -------------------------------------------------------------------------------- 1 | // icalBuddy-specific unit test 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import "IcalBuddyUnitTest.h" 31 | 32 | 33 | @implementation IcalBuddyUnitTest 34 | 35 | - (id) init 36 | { 37 | if (!(self = [super init])) 38 | return nil; 39 | 40 | return self; 41 | } 42 | 43 | - (void) dealloc 44 | { 45 | [super dealloc]; 46 | } 47 | 48 | 49 | - (AppOptions) setUpWithNowDate:(NSDate *)date opts:(NSArray *)argsArr 50 | { 51 | int argc = [argsArr count]; 52 | char **argv = (char **) malloc(sizeof(char *) * (argc + 1)); 53 | for (int i = 0; i < argc; i++) 54 | { 55 | NSString *s = [argsArr objectAtIndex:i]; 56 | const char *cstr = [s UTF8String]; 57 | int len = strlen(cstr); 58 | char *cstr_copy = (char *) malloc(sizeof(char) * (len + 1)); 59 | strcpy(cstr_copy, cstr); 60 | argv[i] = cstr_copy; 61 | } 62 | 63 | 64 | 65 | NSMutableAttributedString *stdoutBuffer = kEmptyMutableAttributedString; 66 | 67 | now = date; 68 | today = dateForStartOfDay(now); 69 | 70 | // don't read any config or L10N files 71 | NSString *configFilePath = @""; 72 | NSString *L10nFilePath = @""; 73 | readConfigAndL10NFilePathArgs(argc, argv, &configFilePath, &L10nFilePath); 74 | 75 | initL10N(L10nFilePath); 76 | 77 | AppOptions opts = NEW_DEFAULT_APP_OPTIONS; 78 | PrettyPrintOptions prettyPrintOptions = getDefaultPrettyPrintOptions(); 79 | 80 | // read and validate general configuration file 81 | NSMutableDictionary *configDict = nil; 82 | NSDictionary *userSuppliedFormattingConfigDict = nil; 83 | if (configFilePath == nil) 84 | configFilePath = [kConfigFilePath stringByExpandingTildeInPath]; 85 | if (configFilePath != nil && [configFilePath length] > 0) 86 | { 87 | readArgsFromConfigFile(&opts, &prettyPrintOptions, configFilePath, &configDict); 88 | if (configDict != nil) 89 | userSuppliedFormattingConfigDict = [configDict objectForKey:@"formatting"]; 90 | } 91 | 92 | readProgramArgs(&opts, &prettyPrintOptions, argc, argv); 93 | 94 | NSArray *propertySeparators = nil; 95 | processAppOptions(&opts, &prettyPrintOptions, &propertySeparators); 96 | initFormatting(nil, propertySeparators); 97 | initPrettyPrint(stdoutBuffer, prettyPrintOptions); 98 | 99 | return opts; 100 | } 101 | 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /tests/unit/UnitTest.m: -------------------------------------------------------------------------------- 1 | // icalBuddy unit test 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import "UnitTest.h" 31 | #import 32 | 33 | 34 | @implementation UnitTest 35 | 36 | - (id) init 37 | { 38 | if (!(self = [super init])) 39 | return nil; 40 | 41 | return self; 42 | } 43 | 44 | - (void) dealloc 45 | { 46 | [super dealloc]; 47 | } 48 | 49 | - (NSString *) getClassName 50 | { 51 | return [NSString stringWithUTF8String:class_getName([self class])]; 52 | } 53 | 54 | - (NSArray *) getMethodNames 55 | { 56 | NSMutableArray *methodsArr = [NSMutableArray array]; 57 | 58 | unsigned int numMethods; 59 | Method *methods = class_copyMethodList([self class], &numMethods); 60 | for (unsigned i = 0; i < numMethods; i++) 61 | [methodsArr addObject:[NSString stringWithUTF8String:sel_getName(method_getName(methods[i]))]]; 62 | free(methods); 63 | 64 | return methodsArr; 65 | } 66 | 67 | - (NSArray *) getTestMethodNames 68 | { 69 | NSMutableArray *testMethods = [NSMutableArray array]; 70 | 71 | NSArray *methodNames = [self getMethodNames]; 72 | for (NSString *name in methodNames) 73 | { 74 | if ([name hasPrefix:@"test"]) 75 | [testMethods addObject:name]; 76 | } 77 | 78 | return testMethods; 79 | } 80 | 81 | 82 | - (TestInfo *) runTests 83 | { 84 | TestInfo *testInfo = [[[TestInfo alloc] init] autorelease]; 85 | 86 | SEL setUpSel = @selector(setUp); 87 | SEL tearDownSel = @selector(tearDown); 88 | 89 | PRINTLN_BOLD(@"------------------------------------------------"); 90 | PRINTLN_BOLD(@"TEST CLASS: %@", [self getClassName]); 91 | 92 | if ([self respondsToSelector:setUpSel]) 93 | { 94 | PRINTLN_B(@"• setUp"); 95 | [self performSelector:setUpSel]; 96 | } 97 | 98 | NSArray *testMethods = [self getTestMethodNames]; 99 | for (NSString *name in testMethods) 100 | { 101 | PRINTLN_B(@"• Running test: %@", name); 102 | BOOL success = [[self performSelector:NSSelectorFromString(name)] boolValue]; 103 | 104 | testInfo.numTests++; 105 | if (success) 106 | { 107 | testInfo.numSuccesses++; 108 | PRINTLN_G(@"+ TEST %@ OK.", name); 109 | } 110 | else 111 | PRINTLN_R(@"- TEST %@ FAILED.", name); 112 | } 113 | 114 | if ([self respondsToSelector:tearDownSel]) 115 | { 116 | PRINTLN_B(@"• tearDown"); 117 | [self performSelector:tearDownSel]; 118 | } 119 | 120 | return testInfo; 121 | } 122 | 123 | 124 | @end 125 | -------------------------------------------------------------------------------- /HGCLIAutoUpdater.h: -------------------------------------------------------------------------------- 1 | // CLI app auto-update code 2 | // 3 | // http://hasseg.org/ 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2010 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import 31 | #import "ANSIEscapeHelper.h" 32 | 33 | 34 | #define kHGCLIAutoUpdateErrorDomain @"org.hasseg.autoUpdate" 35 | #define kServerConnectTimeout 10.0 36 | 37 | 38 | #define NS_ERROR(c,d) [NSError\ 39 | errorWithDomain:kHGCLIAutoUpdateErrorDomain\ 40 | code:(c)\ 41 | userInfo:[NSDictionary\ 42 | dictionaryWithObject:(d)\ 43 | forKey:NSLocalizedDescriptionKey]] 44 | 45 | 46 | // helper method: compare three-part version number strings (e.g. "1.12.3") 47 | NSComparisonResult versionNumberCompare(NSString *first, NSString *second); 48 | 49 | 50 | @interface HGCLIAutoUpdater : NSObject 51 | { 52 | ANSIEscapeHelper *ansiEscapeHelper; 53 | NSString *versionCheckHeaderName; 54 | 55 | NSString *appName; 56 | NSString *currentVersionStr; 57 | NSString *latestVersionStr; 58 | 59 | id delegate; 60 | } 61 | 62 | @property(retain) id delegate; 63 | @property(retain) ANSIEscapeHelper *ansiEscapeHelper; 64 | @property(copy) NSString *appName; 65 | @property(copy) NSString *versionCheckHeaderName; 66 | @property(copy) NSString *currentVersionStr; 67 | @property(copy) NSString *latestVersionStr; 68 | 69 | - (id) initWithAppName:(NSString *)aAppName currentVersionStr:(NSString *)aCurrentVersionStr; 70 | 71 | - (void) checkForUpdatesWithUI; 72 | 73 | // initiate auto-update 74 | - (void) autoUpdateSelfFromURL:(NSURL *)latestVersionZIPURL; 75 | 76 | // returns latest version number (as string) if an update is found online, 77 | // or nil if no update was found. on error, errorStr will contain 78 | // an error message. 79 | - (NSString *) latestUpdateVersionOnServerWithError:(NSError **)error; 80 | 81 | 82 | @end 83 | 84 | 85 | @interface NSObject (HGCLIAutoUpdaterDelegate) 86 | 87 | - (NSURL *) latestVersionCheckURLWithCurrentVersion:(NSString *)currentVersionStr; 88 | - (NSURL *) latestVersionInfoWebURLWithCurrentVersion:(NSString *)currentVersionStr latestVersion:(NSString *)latestVersionStr; 89 | - (NSURL *) releaseNotesHTMLURLWithCurrentVersion:(NSString *)currentVersionStr latestVersion:(NSString *)latestVersionStr; 90 | - (NSURL *) latestVersionZIPURLWithCurrentVersion:(NSString *)currentVersionStr latestVersion:(NSString *)latestVersionStr; 91 | - (NSString *) commandToRunInstaller; 92 | 93 | - (void) autoUpdater:(HGCLIAutoUpdater *)autoUpdater willInstallVersion:(NSString *)latestVersionStr; 94 | - (void) autoUpdater:(HGCLIAutoUpdater *)autoUpdater didInstallVersion:(NSString *)latestVersionStr; 95 | - (void) autoUpdater:(HGCLIAutoUpdater *)autoUpdater didFailToInstallVersion:(NSString *)latestVersionStr; 96 | 97 | @end 98 | -------------------------------------------------------------------------------- /examples/examples.css: -------------------------------------------------------------------------------- 1 | 2 | /* CSS for the usage examples HTML (generated via make) */ 3 | 4 | .fg-black { color: black; } 5 | .fg-red { color: red; } 6 | .fg-green { color: #33cc00; } 7 | .fg-yellow { color: yellow; } 8 | .fg-blue { color: blue; } 9 | .fg-magenta { color: magenta; } 10 | .fg-cyan { color: cyan; } 11 | .fg-white { color: white; } 12 | 13 | .bg-black { background-color: black; } 14 | .bg-red { background-color: red; } 15 | .bg-green { background-color: #33cc00; } 16 | .bg-yellow { background-color: yellow; } 17 | .bg-blue { background-color: blue; } 18 | .bg-magenta { background-color: magenta; } 19 | .bg-cyan { background-color: cyan; } 20 | .bg-white { background-color: white; } 21 | 22 | .bright-fg-black { color: black; } 23 | .bright-fg-red { color: red; } 24 | .bright-fg-green { color: #33cc00; } 25 | .bright-fg-yellow { color: yellow; } 26 | .bright-fg-blue { color: blue; } 27 | .bright-fg-magenta { color: magenta; } 28 | .bright-fg-cyan { color: cyan; } 29 | .bright-fg-white { color: white; } 30 | 31 | .bright-bg-black { background-color: black; } 32 | .bright-bg-red { background-color: red; } 33 | .bright-bg-green { background-color: #33cc00; } 34 | .bright-bg-yellow { background-color: yellow; } 35 | .bright-bg-blue { background-color: blue; } 36 | .bright-bg-magenta { background-color: magenta; } 37 | .bright-bg-cyan { background-color: cyan; } 38 | .bright-bg-white { background-color: white; } 39 | 40 | .bold { font-weight: bold; } 41 | 42 | .underlined { text-decoration: underline; } 43 | .double-underlined { text-decoration: underline; } 44 | 45 | html, body { 46 | padding: 0; 47 | margin: 0 0 100px 0; 48 | font-family: Baskerville, Times, "Times New Roman", serif; 49 | } 50 | 51 | #main { 52 | width: 800px; 53 | padding: 0; 54 | margin: 0; 55 | } 56 | 57 | #visualParams { 58 | width: 300px; 59 | position: fixed; 60 | left: 810px; 61 | top: 0; 62 | background: #eee; 63 | padding: 0px 10px 20px 10px; 64 | } 65 | 66 | #visualParams > form > ul > li > em { 67 | font-weight: bold; 68 | font-style: normal; 69 | color: #777; 70 | } 71 | #visualParams ul li { 72 | margin-top: 3px; 73 | } 74 | 75 | #main > p, #main > pre, #main > div, #main > table { 76 | margin-left: 200px; 77 | } 78 | 79 | #title { 80 | margin: 0 0 10px 0 !important; 81 | background: #555; 82 | color: white; 83 | padding: 30px 0 20px 200px; 84 | font-family: Baskerville, Georgia, Times, "Times New Roman", serif; 85 | font-size: 35px; 86 | font-weight: bold; 87 | font-style: italic; 88 | } 89 | 90 | h1, h2, h3 { 91 | padding-left: 200px; 92 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 93 | border-bottom: 1px solid #999; 94 | margin-top: 40px; 95 | } 96 | 97 | h1 { 98 | font-size: 24px; 99 | background: #888; 100 | color: white; 101 | -moz-border-radius-topright: 15px; 102 | -moz-border-radius-bottomright: 15px; 103 | -webkit-border-top-right-radius: 15px; 104 | -webkit-border-bottom-right-radius: 15px; 105 | border-top-right-radius: 15px; 106 | border-bottom-right-radius: 15px; 107 | } 108 | 109 | h2 { 110 | font-size: 18px; 111 | } 112 | 113 | h3 { 114 | font-size: 16px; 115 | } 116 | 117 | code { 118 | border: 1px solid #ddd; 119 | background: #eee; 120 | padding: 0 4px 0 4px; 121 | white-space: nowrap; 122 | } 123 | 124 | code.output { 125 | max-width: 320px; 126 | background: black; 127 | color: white; 128 | display: block; 129 | border: 1px solid black; 130 | padding: 10px; 131 | float: right; 132 | margin: 0 0 10px 20px; 133 | overflow: hidden; 134 | } 135 | 136 | pre.command { 137 | border: 1px dotted #ff9999; 138 | background: #ffffcc; 139 | padding: 10px; 140 | } 141 | 142 | pre.command code { 143 | border: none; 144 | background: none; 145 | white-space: pre-wrap; 146 | } 147 | 148 | table.formattingConfig { 149 | font-family: "Lucida Sans", sans-serif; 150 | font-size: 13px; 151 | border-collapse: collapse; 152 | } 153 | table.formattingConfig th, table.formattingConfig td { 154 | padding: 2px 5px; 155 | border: 1px solid #999; 156 | } 157 | table.formattingConfig th { 158 | background: #999; 159 | color: white; 160 | } 161 | 162 | -------------------------------------------------------------------------------- /icalBuddyPrettyPrint.h: -------------------------------------------------------------------------------- 1 | // icalBuddy pretty printing functions 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import 31 | #import "calendarStoreImport.h" 32 | #import "icalBuddyDefines.h" 33 | 34 | 35 | typedef struct 36 | { 37 | // the order of properties in the output 38 | NSArray *propertyOrder; 39 | 40 | // the prefix strings 41 | NSString *prefixStrBullet; 42 | NSString *prefixStrBulletAlert; 43 | NSString *sectionSeparatorStr; 44 | 45 | NSString *timeFormatStr; 46 | NSString *dateFormatStr; 47 | NSSet *includedEventProperties; 48 | NSSet *excludedEventProperties; 49 | NSSet *includedTaskProperties; 50 | NSSet *excludedTaskProperties; 51 | NSString *notesNewlineReplacement; 52 | 53 | BOOL displayRelativeDates; 54 | BOOL excludeEndDates; 55 | BOOL useCalendarColorsForTitles; 56 | BOOL showUIDs; 57 | NSUInteger maxNumPrintedItems; // 0 = no limit 58 | NSUInteger numPrintedItems; 59 | } PrettyPrintOptions; 60 | 61 | 62 | #define SECTION_TO_NSVALUE(x) [NSValue valueWithBytes:&(x) objCType:@encode(PrintSection)] 63 | #define NSVALUE_TO_SECTION(x, y) [(x) getValue:&(y)] 64 | 65 | typedef struct 66 | { 67 | NSString *title; 68 | NSArray *items; 69 | NSDate *eventsContextDay; 70 | } PrintSection; 71 | 72 | 73 | typedef struct 74 | { 75 | BOOL singleDay; // in the contex of a single day (for events) (i.e. don't print out full dates) 76 | BOOL calendarAgnostic; // calendar-agnostic (i.e. don't print out the calendar name) 77 | BOOL withoutPropNames; // without property names (i.e. print only the values) 78 | BOOL calendarColorsForSectionTitles; 79 | BOOL priorityAgnostic; 80 | NSUInteger maxNumPrintedAttendees; 81 | NSUInteger maxNumNoteCharacters; 82 | } CalItemPrintOption; 83 | 84 | 85 | typedef enum datePrintOption 86 | { 87 | DATE_PRINT_OPTION_NONE = 0, 88 | ONLY_DATE = (1 << 0), 89 | ONLY_TIME = (1 << 1), 90 | DATE_AND_TIME = (1 << 2) 91 | } DatePrintOption; 92 | 93 | 94 | void initPrettyPrint(NSMutableAttributedString *aOutputBuffer, PrettyPrintOptions opts); 95 | PrettyPrintOptions getDefaultPrettyPrintOptions(); 96 | 97 | NSString *dateStr(NSDate *date, DatePrintOption printOption); 98 | NSString *localizedPriority(CalPriority priority); 99 | NSString *localizedPriorityTitle(CalPriority priority); 100 | 101 | NSMutableAttributedString* getEventPropStr(NSString *propName, CalEvent *event, CalItemPrintOption printOptions, NSDate *contextDay); 102 | NSMutableAttributedString* getTaskPropStr(NSString *propName, CalTask *task, CalItemPrintOption printOptions); 103 | 104 | void printCalEvent(CalEvent *event, CalItemPrintOption printOptions, NSDate *contextDay); 105 | void printCalTask(CalTask *task, CalItemPrintOption printOptions); 106 | void printItemSections(NSArray *sections, CalItemPrintOption printOptions); 107 | 108 | void printAllCalendars(AppOptions *opts); 109 | 110 | void flushOutputBuffer(NSMutableAttributedString *buffer, AppOptions *opts, NSDictionary *formattedKeywords); 111 | 112 | -------------------------------------------------------------------------------- /tests/regression/integrationRegressionTests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | 4 | import os 5 | import sys 6 | import subprocess 7 | from datetime import datetime 8 | from ansihelper import * 9 | 10 | 11 | def read_commands_file(path): 12 | f = open(path, 'r') 13 | ret = [] 14 | for line in f.readlines(): 15 | stripped = line.strip() 16 | if stripped.startswith('#') or len(stripped) == 0: 17 | continue 18 | ret.append(stripped) 19 | f.close() 20 | return ret 21 | 22 | 23 | def run_command(command_str): 24 | process = subprocess.Popen(command_str, shell=True, 25 | stdout=subprocess.PIPE, 26 | stderr=subprocess.PIPE) 27 | stdout, stderr = process.communicate() 28 | return stdout 29 | 30 | 31 | def write_failure_log(logfile_path, failed_commands, ok_icalbuddy, 32 | tested_icalbuddy): 33 | if os.path.exists(logfile_path): 34 | os.unlink(logfile_path) 35 | f = open(logfile_path, 'w') 36 | 37 | f.write('icalBuddy integration regression test failures log\n') 38 | f.write('%s\n' % datetime.now()) 39 | f.write('\n') 40 | f.write('"ok" icalBuddy at: %s\n' % ok_icalbuddy) 41 | f.write('"tested" icalBuddy at: %s\n' % tested_icalbuddy) 42 | f.write('\n') 43 | 44 | for command_dict in failed_commands: 45 | f.write('=========================================================' 46 | '==========================\n') 47 | f.write('COMMAND: %s\n' % command_dict['command']) 48 | f.write('\n') 49 | f.write('OK-OUTPUT: -----------------------------------------------\n') 50 | f.write(command_dict['ok-out']) 51 | f.write('\n\n') 52 | f.write('TESTED-OUTPUT: -------------------------------------------\n') 53 | f.write(command_dict['tested-out']) 54 | f.write('\n\n') 55 | 56 | f.close() 57 | 58 | 59 | if __name__ == '__main__': 60 | 61 | my_path = sys.path[0] 62 | 63 | ok_icalbuddy_path = '/usr/local/bin/icalBuddy' 64 | tested_icalbuddy_path = os.path.abspath(my_path + '/../../icalBuddy') 65 | commands_path = os.path.abspath(my_path 66 | + '/integrationRegressionTestCommands.txt') 67 | logfile_path = os.path.abspath(my_path + '/last-failures.log') 68 | 69 | commands = read_commands_file(commands_path) 70 | 71 | num_commands = len(commands) 72 | num_failed = 0 73 | 74 | print 75 | print 'Using "ok" icalBuddy at:', blue('%s' % ok_icalbuddy_path) 76 | print 'Using "tested" icalBuddy at:', cyan('%s' % tested_icalbuddy_path) 77 | print 78 | print bold('%i commands to test. press enter to start.' % num_commands) 79 | print bold('--------------------------------------------') 80 | print 81 | try: 82 | raw_input() 83 | except KeyboardInterrupt: 84 | sys.exit(2) 85 | 86 | failure_log_data = [] 87 | 88 | for command in commands: 89 | sys.stdout.write(blue(command)) 90 | sys.stdout.flush() 91 | 92 | ok_icalbuddy_command = command.replace('icalBuddy', ok_icalbuddy_path) 93 | tested_icalbuddy_command = command.replace('icalBuddy', 94 | tested_icalbuddy_path) 95 | 96 | ok_icalbuddy_out = run_command(ok_icalbuddy_command) 97 | tested_icalbuddy_out = run_command(tested_icalbuddy_command) 98 | 99 | failed = (ok_icalbuddy_out != tested_icalbuddy_out) 100 | 101 | sys.stdout.write(' - %s\n' % (red('FAIL') if failed else green('OK'))) 102 | sys.stdout.flush() 103 | 104 | if (failed): 105 | num_failed += 1 106 | failure_log_data.append({'command': command, 107 | 'ok-out': ok_icalbuddy_out, 108 | 'tested-out': tested_icalbuddy_out}) 109 | 110 | print 111 | if num_failed == 0: 112 | print bold('All commands succeeded.') 113 | else: 114 | write_failure_log(logfile_path, failure_log_data, ok_icalbuddy_path, 115 | tested_icalbuddy_path) 116 | print red('%i/%i commands failed.' % (num_failed, num_commands)) 117 | print 'Failure log written to: %s' % logfile_path 118 | sys.exit(1) 119 | 120 | -------------------------------------------------------------------------------- /tests/unit/UnitTest.h: -------------------------------------------------------------------------------- 1 | // icalBuddy unit test 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import 31 | #import "TestInfo.h" 32 | #import "../../HGUtils.h" 33 | #import "../../HGCLIUtils.h" 34 | 35 | #define ARR(...) [NSArray arrayWithObjects:__VA_ARGS__, nil] 36 | #define DATE(x) [NSDate dateWithString:(x)] 37 | 38 | #define RED(...) strConcat(@"\e[31m", [NSString stringWithFormat:__VA_ARGS__], @"\e[39m", nil) 39 | #define GREEN(...) strConcat(@"\e[32m", [NSString stringWithFormat:__VA_ARGS__], @"\e[39m", nil) 40 | #define YELLOW(...) strConcat(@"\e[33m", [NSString stringWithFormat:__VA_ARGS__], @"\e[39m", nil) 41 | #define BLUE(...) strConcat(@"\e[34m", [NSString stringWithFormat:__VA_ARGS__], @"\e[39m", nil) 42 | #define MAGENTA(...) strConcat(@"\e[35m", [NSString stringWithFormat:__VA_ARGS__], @"\e[39m", nil) 43 | #define CYAN(...) strConcat(@"\e[36m", [NSString stringWithFormat:__VA_ARGS__], @"\e[39m", nil) 44 | #define BOLD(...) strConcat(@"\e[1m", [NSString stringWithFormat:__VA_ARGS__], @"\e[22m", nil) 45 | 46 | #define PRINTLN_R(...) Printf(strConcat(RED(__VA_ARGS__), @"\n", nil)) 47 | #define PRINTLN_G(...) Printf(strConcat(GREEN(__VA_ARGS__), @"\n", nil)) 48 | #define PRINTLN_Y(...) Printf(strConcat(YELLOW(__VA_ARGS__), @"\n", nil)) 49 | #define PRINTLN_B(...) Printf(strConcat(BLUE(__VA_ARGS__), @"\n", nil)) 50 | #define PRINTLN_BOLD(...) Printf(strConcat(BOLD(__VA_ARGS__), @"\n", nil)) 51 | 52 | #define HG_FAIL(t,m) Printf(\ 53 | strConcat(\ 54 | @"\e[31m- ", (t), @":\e[39m ",\ 55 | (m),\ 56 | RED(@" [%s:%u]", __FILE__, __LINE__),\ 57 | @"\n", nil\ 58 | )\ 59 | );\ 60 | return [NSNumber numberWithBool:NO]; 61 | 62 | #define HG_FAIL_AB(t,m,a,b) Printf(\ 63 | strConcat(\ 64 | @"\e[31m- ", (t), @":\e[39m ",\ 65 | [NSString stringWithFormat:(m), #a, (b), (a)],\ 66 | RED(@" [%s:%u]", __FILE__, __LINE__),\ 67 | @"\n", nil\ 68 | )\ 69 | );\ 70 | return [NSNumber numberWithBool:NO]; 71 | 72 | #define HG_ASSERT_EQUALS(a,b) {if ((a) != (b)) { HG_FAIL_AB(@"assert equals", @"\e[36m%s\e[39m should be \e[35m%d\e[39m but was \e[33m%d\e[39m instead", a, b) }} 73 | #define HG_ASSERT_OBJ_EQUALS(a,b) {if (![(a) isEqual:(b)]) { HG_FAIL_AB(@"assert obj equals", @"\e[36m%s\e[39m should be \e[35m%@\e[39m but was \e[33m%@\e[39m instead", a, b) }} 74 | #define HG_ASSERT_NOT_NIL(a) {if ((a) == nil) { HG_FAIL(@"assert not nil", @"") }} 75 | #define HG_ASSERT_TRUE(a) {if (!(a)) { HG_FAIL(@"assert true", @"") }} 76 | #define HG_ASSERT_FALSE(a) {if (a) { HG_FAIL(@"assert false", @"") }} 77 | //#define HG_ASSERT_THROWS(a,m) 78 | //#define HG_ASSERT_NO_THROW(a,m) 79 | #define HG_TEST_DONE return [NSNumber numberWithBool:YES] 80 | #define HG_TEST_RETURN_TYPE NSNumber * 81 | 82 | 83 | @interface UnitTest : NSObject 84 | { 85 | 86 | } 87 | 88 | - (TestInfo *) runTests; 89 | 90 | 91 | @end 92 | -------------------------------------------------------------------------------- /tests/regression/integrationRegressionTestCommands.txt: -------------------------------------------------------------------------------- 1 | icalBuddy -d -cf "" -sc eventsToday+3 2 | icalBuddy -d -cf "" -sc eventsToday 3 | icalBuddy -d -cf "" -sc uncompletedTasks 4 | icalBuddy -d -cf "" -sc tasksDueBefore:'2010-07-15' 5 | icalBuddy -d -cf "" -sc eventsNow 6 | icalBuddy -d -cf "" -sc eventsFrom:2010-09-10 to:2010-09-13 7 | 8 | icalBuddy -d -cf "" -sd eventsToday+3 9 | icalBuddy -d -cf "" -sd eventsToday 10 | icalBuddy -d -cf "" -sd uncompletedTasks 11 | icalBuddy -d -cf "" -sd tasksDueBefore:'2010-07-15' 12 | icalBuddy -d -cf "" -sd eventsNow 13 | icalBuddy -d -cf "" -sd eventsFrom:2010-09-10 to:2010-09-13 14 | 15 | icalBuddy -d -cf "" -sd -ss '****\n' eventsToday+3 16 | icalBuddy -d -cf "" -sd -ss '****\n' eventsToday 17 | icalBuddy -d -cf "" -sd -ss '****\n' uncompletedTasks 18 | icalBuddy -d -cf "" -sd -ss '****\n' tasksDueBefore:'2010-07-15' 19 | icalBuddy -d -cf "" -sd -ss '****\n' eventsNow 20 | icalBuddy -d -cf "" -sd -ss '****\n' eventsFrom:2010-09-10 to:2010-09-13 21 | 22 | icalBuddy -d -cf "" -sd -sed eventsToday+3 23 | icalBuddy -d -cf "" -sd -sed eventsToday 24 | #these hang: 25 | #icalBuddy -d -cf "" -sd -sed uncompletedTasks 26 | #icalBuddy -d -cf "" -sd -sed tasksDueBefore:'2010-07-15' 27 | icalBuddy -d -cf "" -sd -sed eventsNow 28 | icalBuddy -d -cf "" -sd -sed eventsFrom:2010-09-10 to:2010-09-13 29 | 30 | icalBuddy -d -cf "" eventsToday+3 31 | icalBuddy -d -cf "" eventsToday 32 | icalBuddy -d -cf "" uncompletedTasks 33 | icalBuddy -d -cf "" tasksDueBefore:'2010-07-15' 34 | icalBuddy -d -cf "" eventsNow 35 | icalBuddy -d -cf "" eventsFrom:2010-09-10 to:2010-09-13 36 | 37 | icalBuddy -d -cf "" -f -sc -nrd eventsToday+3 38 | icalBuddy -d -cf "" -f -sc -nrd eventsToday 39 | icalBuddy -d -cf "" -f -sc -nrd uncompletedTasks 40 | icalBuddy -d -cf "" -f -sc -nrd tasksDueBefore:'2010-07-15' 41 | icalBuddy -d -cf "" -f -sc -nrd eventsNow 42 | icalBuddy -d -cf "" -f -sc -nrd eventsFrom:2010-09-10 to:2010-09-13 43 | 44 | icalBuddy -d -cf "" -f -sc -nc eventsToday+3 45 | icalBuddy -d -cf "" -f -sc -nc eventsToday 46 | icalBuddy -d -cf "" -f -sc -nc uncompletedTasks 47 | icalBuddy -d -cf "" -f -sc -nc tasksDueBefore:'2010-07-15' 48 | icalBuddy -d -cf "" -f -sc -nc eventsNow 49 | icalBuddy -d -cf "" -f -sc -nc eventsFrom:2010-09-10 to:2010-09-13 50 | 51 | icalBuddy -d -cf "" -f -sc -npn eventsToday+3 52 | icalBuddy -d -cf "" -f -sc -npn eventsToday 53 | icalBuddy -d -cf "" -f -sc -npn uncompletedTasks 54 | icalBuddy -d -cf "" -f -sc -npn tasksDueBefore:'2010-07-15' 55 | icalBuddy -d -cf "" -f -sc -npn eventsNow 56 | icalBuddy -d -cf "" -f -sc -npn eventsFrom:2010-09-10 to:2010-09-13 57 | 58 | icalBuddy -d -cf "" -li 3 eventsToday+3 59 | icalBuddy -d -cf "" -li 3 eventsToday 60 | icalBuddy -d -cf "" -li 3 uncompletedTasks 61 | icalBuddy -d -cf "" -li 3 tasksDueBefore:'2010-07-15' 62 | icalBuddy -d -cf "" -li 3 eventsNow 63 | icalBuddy -d -cf "" -li 3 eventsFrom:2010-09-10 to:2010-09-13 64 | 65 | icalBuddy -d -cf "" -uid eventsToday+3 66 | icalBuddy -d -cf "" -uid eventsToday 67 | icalBuddy -d -cf "" -uid uncompletedTasks 68 | icalBuddy -d -cf "" -uid tasksDueBefore:'2010-07-15' 69 | icalBuddy -d -cf "" -uid eventsNow 70 | icalBuddy -d -cf "" -uid eventsFrom:2010-09-10 to:2010-09-13 71 | 72 | icalBuddy -d -cf "" -eed eventsToday+3 73 | icalBuddy -d -cf "" -eed eventsToday 74 | icalBuddy -d -cf "" -eed uncompletedTasks 75 | icalBuddy -d -cf "" -eed tasksDueBefore:'2010-07-15' 76 | icalBuddy -d -cf "" -eed eventsNow 77 | icalBuddy -d -cf "" -eed eventsFrom:2010-09-10 to:2010-09-13 78 | 79 | icalBuddy -d -cf "" -n eventsToday+3 80 | icalBuddy -d -cf "" -n eventsToday 81 | 82 | icalBuddy -d -cf "" -iep 'url,datetime' eventsToday+3 83 | icalBuddy -d -cf "" -eep 'location,datetime' eventsToday+3 84 | 85 | icalBuddy -d -cf "" -std uncompletedTasks 86 | icalBuddy -d -cf "" -std tasksDueBefore:'2010-07-15' 87 | 88 | icalBuddy -d -cf "" -stda uncompletedTasks 89 | icalBuddy -d -cf "" -stda tasksDueBefore:'2010-07-15' 90 | 91 | icalBuddy -d -cf "" -itp 'url,datetime' uncompletedTasks 92 | icalBuddy -d -cf "" -etp 'location,datetime' uncompletedTasks 93 | 94 | icalBuddy -d -cf "" -ic "Home,Work" eventsToday+10 95 | icalBuddy -d -cf "" -ec "Home" eventsToday+10 96 | 97 | icalBuddy -d -cf "" -b 'x-' -ab 'åå' eventsToday+3 98 | icalBuddy -d -cf "" -b 'x-' -ab 'åå' uncompletedTasks 99 | 100 | icalBuddy -d -cf "" -ps '|--| ;; |' eventsToday+3 101 | icalBuddy -d -cf "" -ps '|--| ;; |' eventsToday 102 | icalBuddy -d -cf "" -ps '|--| ;; |' uncompletedTasks 103 | icalBuddy -d -cf "" -ps '|--| ;; |' tasksDueBefore:'2010-07-15' 104 | icalBuddy -d -cf "" -ps '|--| ;; |' eventsNow 105 | icalBuddy -d -cf "" -ps '|--| ;; |' eventsFrom:2010-09-10 to:2010-09-13 106 | 107 | icalBuddy -d -cf "" -nnr ';;' eventsToday+3 108 | icalBuddy -d -cf "" -nnr ';;' eventsToday 109 | icalBuddy -d -cf "" -nnr ';;' uncompletedTasks 110 | icalBuddy -d -cf "" -nnr ';;' tasksDueBefore:'2010-07-15' 111 | icalBuddy -d -cf "" -nnr ';;' eventsNow 112 | icalBuddy -d -cf "" -nnr ';;' eventsFrom:2010-09-10 to:2010-09-13 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /deployment-files/uninstall.command: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # uninstall script for icalBuddy 4 | # Copyright 2010 Ali Rantakari 5 | # 6 | 7 | import os 8 | from subprocess import Popen, PIPE, STDOUT 9 | 10 | 11 | # search paths configuration 12 | prefixes = ['/usr/local', os.path.expanduser('~')] 13 | bin_paths = ['bin', '.bin'] 14 | man_paths = ['man/man1', 'share/man/man1', '.man/man1', '.share/man/man1'] 15 | 16 | # exit status values 17 | STATUS_OK = 0 18 | STATUS_ERROR = 1 19 | STATUS_NOTHING_TO_UNINSTALL = 10 20 | STATUS_USER_CANCEL = 11 21 | 22 | 23 | def wrap_ansi(s, start_code, end_code): 24 | return '\x1b['+str(start_code)+'m'+s+'\x1b['+str(end_code)+'m' 25 | def wrap_ansi_sgr(s, sgr): 26 | return wrap_ansi(s, sgr, (sgr-(sgr%10)+9)) 27 | def red(s): return wrap_ansi_sgr(s, 31) 28 | def green(s): return wrap_ansi_sgr(s, 32) 29 | def yellow(s): return wrap_ansi_sgr(s, 33) 30 | def blue(s): return wrap_ansi_sgr(s, 34) 31 | def magenta(s): return wrap_ansi_sgr(s, 35) 32 | def cyan(s): return wrap_ansi_sgr(s, 36) 33 | def bold(s): return wrap_ansi(s,1,22) 34 | 35 | 36 | def find_path_under_prefix(name, prefix, bin=True): 37 | paths = bin_paths if bin else man_paths 38 | for path in paths: 39 | p = os.path.join(prefix,path,name) 40 | if os.path.exists(p): return p 41 | return None 42 | 43 | def find_path(name, bin=True): 44 | ret = None 45 | for prefix in prefixes: 46 | ret = find_path_under_prefix(name,prefix,bin=bin) 47 | if ret != None: return ret 48 | return None 49 | 50 | 51 | def move_to_trash(paths): 52 | applescript_format = 'tell application "Finder" to delete every item of {%(paths)s}' 53 | paths_strs = [] 54 | for path in paths: 55 | paths_strs.append('(POSIX file "'+path.replace('"','\\"')+'")') 56 | applescript = applescript_format % {'paths': ','.join(paths_strs)} 57 | 58 | p = Popen(['osascript', '-s','s'], stdin=PIPE, stdout=PIPE, stderr=PIPE) 59 | p_out, p_err = p.communicate(input=applescript) 60 | return STATUS_OK 61 | 62 | 63 | def uninstall(bin_filenames, man_filenames): 64 | all_found_paths = [] 65 | found_bin_paths = {} 66 | found_man_paths = {} 67 | num_found_files = 0 68 | 69 | for b in bin_filenames: 70 | found_path = find_path(bin_filenames[b], bin=True) 71 | if found_path == None: 72 | # can't find binary from hardcoded prefix paths; 73 | # try asking `which`: 74 | p = Popen(['which',bin_filenames[b]], stdout=PIPE) 75 | found_path = p.communicate()[0].strip('\n') 76 | if p.returncode > 0: 77 | found_path = None 78 | else: 79 | # if we find a binary in a directory called "bin" 80 | # through `which`, add the parent of that dir into 81 | # our search prefix path list (so that we'd search 82 | # this prefix for the man pages as well). 83 | found_path_prefix, found_path_leafdir = os.path.split(os.path.dirname(found_path)) 84 | if found_path_leafdir == 'bin': 85 | prefixes.append(found_path_prefix) 86 | if found_path != None: 87 | num_found_files += 1 88 | all_found_paths.append(found_path) 89 | found_bin_paths[b] = found_path 90 | 91 | for m in man_filenames: 92 | found_path = find_path(man_filenames[m], bin=False) 93 | if found_path != None: 94 | num_found_files += 1 95 | all_found_paths.append(found_path) 96 | found_man_paths[m] = found_path 97 | 98 | print 'The following installed files were found:' 99 | print 100 | for b in found_bin_paths: 101 | p = found_bin_paths[b] 102 | print b+': '+(green(p) if p != None else red('Not found')) 103 | for m in found_man_paths: 104 | p = found_man_paths[m] 105 | print m+': '+(green(p) if p != None else red('Not found')) 106 | print 107 | 108 | if num_found_files == 0: 109 | print 'Nothing to uninstall.' 110 | return STATUS_NOTHING_TO_UNINSTALL 111 | 112 | print 'Move the above files to trash?' 113 | r = '' 114 | while (r.lower() not in ['y','n']): 115 | r = raw_input('[y/n]: ') 116 | if r.lower() == 'n': 117 | return STATUS_USER_CANCEL 118 | 119 | return move_to_trash(all_found_paths) 120 | 121 | 122 | 123 | if __name__ == '__main__': 124 | 125 | import sys 126 | 127 | # uninstallable items 128 | man_files = { 129 | 'Man page': 'icalBuddy.1', 130 | 'Config man page': 'icalBuddyConfig.1', 131 | 'Localization man page': 'icalBuddyLocalization.1' 132 | } 133 | bin_files = {'Main executable binary': 'icalBuddy'} 134 | 135 | print '=================================' 136 | print 137 | print 'This script will '+red('remove')+' icalBuddy and related files from your system' 138 | print '(the icalBuddy binary executable, the man pages as well as configuration' 139 | print 'and localization files).' 140 | print 141 | print 'We might need administrator rights to remove some of these files so '+yellow('please') 142 | print yellow('enter your admin password when asked')+'.' 143 | print bold('Press any key to continue uninstalling or Ctrl-C to cancel.') 144 | print 145 | 146 | exit_status = STATUS_OK 147 | try: 148 | r = raw_input() 149 | exit_status = uninstall(bin_files, man_files) 150 | if exit_status == STATUS_OK: 151 | print 152 | print green('icalBuddy has successfully been uninstalled.') 153 | print 154 | except KeyboardInterrupt: 155 | exit_status = STATUS_OK 156 | print 157 | except: 158 | exit_status = STATUS_ERROR 159 | 160 | sys.exit(exit_status) 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /HGCLIUtils.m: -------------------------------------------------------------------------------- 1 | // CLI app utils 2 | // 3 | // http://hasseg.org/ 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2010 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import "HGCLIUtils.h" 31 | 32 | 33 | // the string encoding to use for output 34 | NSStringEncoding outputStrEncoding = NSUTF8StringEncoding; // default 35 | 36 | BOOL debugPrintEnabled = NO; 37 | 38 | 39 | 40 | // helper methods for printing to stdout and stderr 41 | // from: http://www.sveinbjorn.org/objectivec_stdout 42 | // (modified to use non-deprecated version of writeToFile:... 43 | // and allow for using the "string format" syntax) 44 | 45 | 46 | 47 | void Print(NSString *aStr) 48 | { 49 | [aStr writeToFile:@"/dev/stdout" atomically:NO encoding:NSUTF8StringEncoding error:NULL]; 50 | } 51 | 52 | // other Printf functions call this, and you call them 53 | void RealPrintf(NSString *aStr, NSString *aFile, va_list opts) 54 | { 55 | NSString *str = [ 56 | [[NSString alloc] 57 | initWithFormat:aStr 58 | locale:[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] 59 | arguments:opts 60 | ] autorelease 61 | ]; 62 | 63 | [str writeToFile:aFile atomically:NO encoding:NSUTF8StringEncoding error:NULL]; 64 | } 65 | 66 | void Printf(NSString *aStr, ...) 67 | { 68 | va_list argList; 69 | va_start(argList, aStr); 70 | RealPrintf(aStr, @"/dev/stdout", argList); 71 | va_end(argList); 72 | } 73 | 74 | void PrintfErr(NSString *aStr, ...) 75 | { 76 | va_list argList; 77 | va_start(argList, aStr); 78 | RealPrintf(aStr, @"/dev/stderr", argList); 79 | va_end(argList); 80 | } 81 | 82 | void DebugPrintf(NSString *aStr, ...) 83 | { 84 | if (!debugPrintEnabled) 85 | return; 86 | 87 | NSString *str = strConcat(@"icalBuddy: ", aStr, nil); 88 | 89 | va_list argList; 90 | va_start(argList, aStr); 91 | RealPrintf(str, @"/dev/stderr", argList); 92 | va_end(argList); 93 | } 94 | 95 | 96 | 97 | 98 | #define UNICHAR_NEWLINE 10 99 | #define UNICHAR_TAB 9 100 | #define UNICHAR_SPACE 32 101 | #define TAB_STOP_LENGTH 4 102 | 103 | void wordWrapMutableAttrStr(NSMutableAttributedString *mutableAttrStr, NSUInteger width) 104 | { 105 | // replace tabs with spaces to avoid problems with different programs 106 | // (that would display our output) using different tab stop lengths: 107 | replaceInMutableAttrStr(mutableAttrStr, @"\t", ATTR_STR(WHITESPACE(TAB_STOP_LENGTH))); 108 | 109 | NSString *str = [[mutableAttrStr string] copy]; 110 | 111 | NSAttributedString *newlineAttrStr = ATTR_STR(@"\n"); 112 | 113 | // characters we'll consider as indentation: 114 | NSCharacterSet *indentChars = [NSCharacterSet characterSetWithCharactersInString:@" •"]; 115 | 116 | // find all input string indices where we want to 117 | // wrap the line 118 | NSUInteger strLength = [str length]; 119 | NSUInteger strIndex = 0; 120 | NSUInteger currentLineLength = 0; 121 | NSUInteger lastWhitespaceIndex = 0; 122 | unichar currentUnichar = 0; 123 | BOOL lastCharWasWhitespace = NO; 124 | BOOL lastCharWasIndentation = NO; 125 | NSUInteger numAddedChars = 0; 126 | NSUInteger currentLineIndentAmount = 0; 127 | while(strIndex < strLength) 128 | { 129 | if (width <= currentLineLength) 130 | { 131 | // insert newline at the wrap index, eating one whitespace 132 | // *if* we're wrapping at a whitespace (i.e. don't eat characters 133 | // if we've been forced to wrap in the middle of a word) 134 | 135 | NSUInteger indexToWrapAt = ((0 < lastWhitespaceIndex) ? lastWhitespaceIndex : strIndex) + numAddedChars; 136 | NSUInteger lengthToReplace = ((lastWhitespaceIndex != 0)?1:0); 137 | NSRange replaceRange = NSMakeRange(indexToWrapAt, lengthToReplace); 138 | 139 | NSAttributedString *replaceStr = nil; 140 | if (currentLineIndentAmount == 0) 141 | replaceStr = newlineAttrStr; 142 | else 143 | replaceStr = ATTR_STR(strConcat(@"\n", WHITESPACE(currentLineIndentAmount), nil)); 144 | 145 | [mutableAttrStr 146 | replaceCharactersInRange:replaceRange 147 | withAttributedString:replaceStr 148 | ]; 149 | 150 | numAddedChars += [replaceStr length] - lengthToReplace; 151 | 152 | lastWhitespaceIndex = 0; 153 | currentLineLength = (strIndex-(indexToWrapAt-numAddedChars)); 154 | } 155 | else 156 | { 157 | currentUnichar = [str characterAtIndex:strIndex]; 158 | 159 | if ((lastCharWasIndentation || currentLineLength == 0) && 160 | [indentChars characterIsMember:currentUnichar] 161 | ) 162 | { 163 | lastCharWasIndentation = YES; 164 | currentLineIndentAmount++; 165 | } 166 | else 167 | lastCharWasIndentation = NO; 168 | 169 | if (currentUnichar == UNICHAR_NEWLINE) 170 | { 171 | lastWhitespaceIndex = 0; 172 | currentLineLength = 0; 173 | currentLineIndentAmount = 0; 174 | } 175 | // we want to wrap at the beginning of the last 176 | // whitespace run of the current line, excluding the 177 | // beginning of the line (doesn't make sense to wrap 178 | // there): 179 | else if (!lastCharWasWhitespace && 180 | 0 < currentLineLength && 181 | currentUnichar == UNICHAR_SPACE 182 | ) 183 | { 184 | lastWhitespaceIndex = strIndex; 185 | currentLineLength++; 186 | } 187 | else 188 | { 189 | currentLineLength++; 190 | } 191 | 192 | lastCharWasWhitespace = (currentUnichar == UNICHAR_SPACE); 193 | } 194 | 195 | strIndex++; 196 | } 197 | 198 | [str release]; 199 | } 200 | 201 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /icalBuddyL10N.m: -------------------------------------------------------------------------------- 1 | // icalBuddy localization functions 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import 31 | #import "HGCLIUtils.h" 32 | #import "icalBuddyL10N.h" 33 | #import "icalBuddyDefines.h" 34 | 35 | 36 | // dictionary for localization values 37 | NSDictionary *L10nStringsDict; 38 | 39 | // default version of L10nStringsDict 40 | NSDictionary *defaultStringsDict; 41 | 42 | 43 | // returns localized, human-readable string corresponding to the 44 | // specified localization dictionary key 45 | NSString* localizedStr(NSString *str) 46 | { 47 | if (str == nil) 48 | return nil; 49 | 50 | if (L10nStringsDict != nil) 51 | { 52 | NSString *localizedStr = [L10nStringsDict objectForKey:str]; 53 | if (localizedStr != nil) 54 | return localizedStr; 55 | } 56 | 57 | NSString *defaultStr = [defaultStringsDict objectForKey:str]; 58 | NSCAssert((defaultStr != nil), @"defaultStr is nil"); 59 | return defaultStr; 60 | } 61 | 62 | 63 | void initL10N(NSString *configFilePath) 64 | { 65 | defaultStringsDict = [NSDictionary dictionaryWithObjectsAndKeys: 66 | @"title", kL10nKeyPropNameTitle, 67 | @"location", kL10nKeyPropNameLocation, 68 | @"notes", kL10nKeyPropNameNotes, 69 | @"url", kL10nKeyPropNameUrl, 70 | @"attendees", kL10nKeyPropNameAttendees, 71 | @"uid", kL10nKeyPropNameUID, 72 | @"due", kL10nKeyPropNameDueDate, 73 | @"no due date", kL10nKeyNoDueDate, 74 | @"priority", kL10nKeyPropNamePriority, 75 | @"%@'s Birthday (age %i)", kL10nKeySomeonesBirthday, 76 | @"%@'s Birthday", kL10nKeySomeonesBirthdayNoAge, 77 | @"My Birthday", kL10nKeyMyBirthday, 78 | @"today", kL10nKeyToday, 79 | @"tomorrow", kL10nKeyTomorrow, 80 | @"yesterday", kL10nKeyYesterday, 81 | @"day before yesterday", kL10nKeyDayBeforeYesterday, 82 | @"day after tomorrow", kL10nKeyDayAfterTomorrow, 83 | @"%d days ago", kL10nKeyXDaysAgo, 84 | @"%d days from now", kL10nKeyXDaysFromNow, 85 | @"this week", kL10nKeyThisWeek, 86 | @"last week", kL10nKeyLastWeek, 87 | @"next week", kL10nKeyNextWeek, 88 | @"%d weeks ago", kL10nKeyXWeeksAgo, 89 | @"%d weeks from now", kL10nKeyXWeeksFromNow, 90 | @"high", kL10nKeyPriorityHigh, 91 | @"medium", kL10nKeyPriorityMedium, 92 | @"low", kL10nKeyPriorityLow, 93 | @"none", kL10nKeyPriorityNone, 94 | @"%@ priority", kL10nKeyPriorityTitle, 95 | @"No priority", kL10nKeyPriorityTitleNone, 96 | @"Low priority", kL10nKeyPriorityTitleLow, 97 | @"Medium priority", kL10nKeyPriorityTitleMedium, 98 | @"High priority", kL10nKeyPriorityTitleHigh, 99 | @" at ", kL10nKeyDateTimeSeparator, 100 | @"Nothing.", kL10nKeyNoItemsInSection, 101 | nil 102 | ]; 103 | readAndValidateL10NConfigFile(configFilePath); 104 | } 105 | 106 | void readAndValidateL10NConfigFile(NSString *filePath) 107 | { 108 | L10nStringsDict = nil; 109 | 110 | if (filePath == nil) 111 | filePath = kL10nFilePath; 112 | 113 | filePath = [filePath stringByExpandingTildeInPath]; 114 | 115 | BOOL L10nFileIsDir; 116 | BOOL L10nFileExists = [[NSFileManager defaultManager] fileExistsAtPath:filePath isDirectory:&L10nFileIsDir]; 117 | if (L10nFileExists && !L10nFileIsDir) 118 | { 119 | BOOL L10nFileIsValid = YES; 120 | 121 | L10nStringsDict = [NSDictionary dictionaryWithContentsOfFile:filePath]; 122 | 123 | if (L10nStringsDict == nil) 124 | { 125 | PrintfErr(@"* Error in localization file \"%@\":\n", filePath); 126 | PrintfErr(@" can not recognize file format -- must be a valid property list\n"); 127 | PrintfErr(@" with a structure specified in the icalBuddyLocalization man page.\n"); 128 | L10nFileIsValid = NO; 129 | } 130 | 131 | if (L10nFileIsValid) 132 | { 133 | // validate some specific keys in localization config 134 | NSDictionary *L10nKeysRequiringSubstrings = [NSDictionary dictionaryWithObjectsAndKeys: 135 | @"%d", kL10nKeyXWeeksFromNow, 136 | @"%d", kL10nKeyXWeeksAgo, 137 | @"%d", kL10nKeyXDaysAgo, 138 | @"%d", kL10nKeyXDaysFromNow, 139 | @"%@", kL10nKeySomeonesBirthday, 140 | @"%@", kL10nKeySomeonesBirthdayNoAge, 141 | nil 142 | ]; 143 | NSString *thisKey; 144 | NSString *thisVal; 145 | NSString *requiredSubstring; 146 | for (thisKey in [L10nKeysRequiringSubstrings allKeys]) 147 | { 148 | requiredSubstring = [L10nKeysRequiringSubstrings objectForKey:thisKey]; 149 | thisVal = [L10nStringsDict objectForKey:thisKey]; 150 | if (thisVal != nil && [thisVal rangeOfString:requiredSubstring].location == NSNotFound) 151 | { 152 | PrintfErr(@"* Error in localization file \"%@\"\n", filePath); 153 | PrintfErr(@" (key: \"%@\", value: \"%@\"):\n", thisKey, thisVal); 154 | PrintfErr(@" value must include %@ to indicate position for a variable.\n", requiredSubstring); 155 | L10nFileIsValid = NO; 156 | } 157 | } 158 | } 159 | 160 | if (!L10nFileIsValid) 161 | { 162 | PrintfErr(@"\nTry running \"man icalBuddyLocalization\" to read the relevant documentation\n"); 163 | PrintfErr(@"and \"plutil '%@'\" to validate the\nfile's property list syntax.\n\n", filePath); 164 | L10nStringsDict = nil; 165 | } 166 | } 167 | } 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /icalBuddyDefines.h: -------------------------------------------------------------------------------- 1 | // icalBuddy definitions 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #define kInternalErrorDomain @"org.hasseg.icalBuddy" 31 | 32 | #define kPropertyListEditorAppName @"Property List Editor" 33 | 34 | // custom date-formatting specifiers 35 | #define kRelativeWeekFormatSpecifier @"%RW" 36 | #define kDayDiffFormatSpecifier @"%RD" 37 | 38 | 39 | // property names 40 | #define kPropName_title @"title" 41 | #define kPropName_location @"location" 42 | #define kPropName_notes @"notes" 43 | #define kPropName_url @"url" 44 | #define kPropName_attendees @"attendees" 45 | #define kPropName_datetime @"datetime" 46 | #define kPropName_priority @"priority" 47 | #define kPropName_UID @"uid" 48 | 49 | 50 | // keys for the "sections" dictionary (see printItemSections()) 51 | #define kSectionDictKey_title @"sectionTitle" 52 | #define kSectionDictKey_items @"sectionItems" 53 | #define kSectionDictKey_eventsContextDay @"eventsContextDay" 54 | 55 | 56 | // output formatting configuration keys 57 | #define kFormatKeySectionTitle @"sectionTitle" 58 | #define kFormatKeyFirstItemLine @"firstItemLine" 59 | #define kFormatKeyBullet @"bullet" 60 | #define kFormatKeyAlertBullet @"alertBullet" 61 | #define kFormatKeyNoItems @"noItems" 62 | #define kFormatKeyCalendarNameInTitle @"calendarNameInTitle" 63 | #define kFormatKeyPriorityValueHigh @"priorityValueHigh" 64 | #define kFormatKeyPriorityValueMedium @"priorityValueMedium" 65 | #define kFormatKeyPriorityValueLow @"priorityValueLow" 66 | // the "suffix" definitions below are used like: 67 | // kPropName_notes + kFormatKeyPropNameSuffix 68 | // ^-- defines the formatting config key for the 69 | // "notes" property name 70 | #define kFormatKeyPropNameSuffix @"Name" 71 | #define kFormatKeyPropValueSuffix @"Value" 72 | 73 | 74 | // output formatting parameters 75 | #define kFormatFgColorPrefix @"fg:" 76 | #define kFormatBgColorPrefix @"bg:" 77 | #define kFormatDoubleUnderlined @"double-underlined" 78 | #define kFormatUnderlined @"underlined" 79 | #define kFormatBold @"bold" 80 | #define kFormatBlink @"blink" 81 | #define kFormatColorBlack @"black" 82 | #define kFormatColorRed @"red" 83 | #define kFormatColorGreen @"green" 84 | #define kFormatColorYellow @"yellow" 85 | #define kFormatColorBlue @"blue" 86 | #define kFormatColorMagenta @"magenta" 87 | #define kFormatColorWhite @"white" 88 | #define kFormatColorCyan @"cyan" 89 | #define kFormatColorBrightBlack @"bright-black" 90 | #define kFormatColorBrightRed @"bright-red" 91 | #define kFormatColorBrightGreen @"bright-green" 92 | #define kFormatColorBrightYellow @"bright-yellow" 93 | #define kFormatColorBrightBlue @"bright-blue" 94 | #define kFormatColorBrightMagenta @"bright-magenta" 95 | #define kFormatColorBrightWhite @"bright-white" 96 | #define kFormatColorBrightCyan @"bright-cyan" 97 | #define kFormatColorCalendarColor @"calendar-color" 98 | 99 | // custom string formatting attribute(s) 100 | #define kBlinkAttributeName @"blinkAttributeName" 101 | #define kSGRCodeBlink 5 102 | #define kSGRCodeBlinkReset 25 103 | 104 | #define kCalendarTypeBirthday @"birthday" 105 | #define kCalendarTypeCalDAV @"caldav" 106 | #define kCalendarTypeiCloud @"icloud" 107 | #define kCalendarTypeExchange @"exchange" 108 | #define kCalendarTypeIMAP @"imap" 109 | #define kCalendarTypeLocal @"local" 110 | #define kCalendarTypeSubscription @"subscription" 111 | 112 | 113 | // default item property order + list of allowed property names (i.e. these must be in 114 | // the default order and include all of the allowed property names) 115 | #define kDefaultPropertyOrder [NSArray arrayWithObjects:kPropName_title, kPropName_location, kPropName_notes, kPropName_url, kPropName_attendees, kPropName_datetime, kPropName_priority, kPropName_UID, nil] 116 | 117 | #define kDefaultPropertySeparators [NSArray arrayWithObjects:@"\n ", nil] 118 | 119 | // general configuration file path 120 | #define kConfigFilePath @"~/.icalBuddyConfig.plist" 121 | 122 | // contents for a new configuration file "stub" 123 | #define kConfigFileStub [NSDictionary dictionaryWithObjectsAndKeys:\ 124 | [NSDictionary dictionary], @"constantArguments",\ 125 | [NSDictionary dictionary], @"formatting",\ 126 | nil\ 127 | ] 128 | 129 | typedef struct 130 | { 131 | BOOL separateByCalendar; 132 | BOOL separateByDate; 133 | BOOL separateByPriority; 134 | 135 | BOOL updatesCheck; 136 | BOOL printVersion; 137 | BOOL includeOnlyEventsFromNowOn; 138 | BOOL useFormatting; 139 | BOOL noCalendarNames; 140 | BOOL sortTasksByDueDate; 141 | BOOL sortTasksByDueDateAscending; 142 | BOOL sectionsForEachDayInSpan; 143 | BOOL noPropNames; 144 | BOOL alwaysShowTodaysSection; 145 | BOOL specificCalFilterPrecedesCalTypeFilter; 146 | BOOL excludeAllDayEvents; 147 | 148 | BOOL output_is_uncompletedTasks; 149 | BOOL output_is_eventsToday; 150 | BOOL output_is_eventsNow; 151 | BOOL output_is_eventsFromTo; 152 | BOOL output_is_tasksDueBefore; 153 | BOOL output_is_undatedUncompletedTasks; 154 | 155 | NSString *output; 156 | NSArray *includeCals; 157 | NSArray *excludeCals; 158 | NSArray *includeCalTypes; 159 | NSArray *excludeCalTypes; 160 | NSString *strEncoding; 161 | NSString *propertyOrderStr; 162 | NSString *propertySeparatorsStr; 163 | NSString *eventsFrom; 164 | NSString *eventsTo; 165 | 166 | NSDate *startDate; 167 | NSDate *endDate; 168 | NSDate *dueBeforeDate; 169 | 170 | NSUInteger maxNumPrintedAttendees; 171 | NSUInteger maxNumNoteCharacters; 172 | } AppOptions; 173 | 174 | #define NEW_DEFAULT_APP_OPTIONS {NO,NO,NO,NO,NO,NO,NO,NO,NO,NO,NO,NO,NO,NO,NO,NO,NO,NO,NO,NO,NO,\ 175 | nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,0,0} 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /deployment-files/install.command: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # install script for icalBuddy 4 | # Copyright 2010 Ali Rantakari 5 | # 6 | 7 | import os 8 | from subprocess import Popen, PIPE, STDOUT 9 | 10 | 11 | # search paths configuration 12 | prefixes = ['/usr/local', os.path.expanduser('~')] 13 | bin_paths = ['bin', '.bin'] 14 | 15 | # exit status values 16 | STATUS_OK = 0 17 | STATUS_ERROR = 1 18 | STATUS_USER_CANCEL = 11 19 | 20 | 21 | def wrap_ansi(s, start_code, end_code): 22 | return '\x1b['+str(start_code)+'m'+s+'\x1b['+str(end_code)+'m' 23 | def wrap_ansi_sgr(s, sgr): 24 | return wrap_ansi(s, sgr, (sgr-(sgr%10)+9)) 25 | def red(s): return wrap_ansi_sgr(s, 31) 26 | def green(s): return wrap_ansi_sgr(s, 32) 27 | def yellow(s): return wrap_ansi_sgr(s, 33) 28 | def blue(s): return wrap_ansi_sgr(s, 34) 29 | def magenta(s): return wrap_ansi_sgr(s, 35) 30 | def cyan(s): return wrap_ansi_sgr(s, 36) 31 | def bold(s): return wrap_ansi(s,1,22) 32 | 33 | 34 | def find_path_under_prefix(name, prefix): 35 | for path in bin_paths: 36 | p = os.path.join(prefix,path,name) 37 | if os.path.exists(p): return p 38 | return None 39 | 40 | def find_path(name): 41 | ret = None 42 | for prefix in prefixes: 43 | ret = find_path_under_prefix(name,prefix) 44 | if ret != None: return ret 45 | return None 46 | 47 | def find_already_installed_prefix(binfile): 48 | found_path = find_path(binfile) 49 | if found_path == None: 50 | # can't find binary from hardcoded prefix paths; 51 | # try asking `which`: 52 | p = Popen(['which',binfile], stdout=PIPE) 53 | found_path = p.communicate()[0].strip('\n') 54 | if p.returncode > 0: found_path = None 55 | 56 | if found_path != None: 57 | found_path_dirname = os.path.dirname(found_path) 58 | found_path_prefix, found_path_leafdir = os.path.split(found_path_dirname) 59 | if found_path_leafdir == 'bin': 60 | return found_path_prefix 61 | return found_path_dirname 62 | 63 | 64 | 65 | if __name__ == '__main__': 66 | 67 | import sys 68 | import shutil 69 | import errno 70 | 71 | homedir = os.path.expanduser('~') 72 | thispath = sys.path[0] 73 | 74 | install_prefix = '/usr/local' # default 75 | 76 | existing_prefix = find_already_installed_prefix('icalBuddy') 77 | if existing_prefix != None: 78 | install_prefix = existing_prefix 79 | 80 | if len(sys.argv) > 1 and sys.argv[1].startswith('--prefix='): 81 | install_prefix = sys.argv[1][len('--prefix='):] 82 | 83 | exit_status = STATUS_OK 84 | installed = False 85 | 86 | while 1 == 1: 87 | 88 | try: 89 | install_prefix = os.path.expanduser(install_prefix) 90 | 91 | files_to_install = { 92 | thispath+'/icalBuddy': os.path.join(install_prefix, 'bin'), 93 | thispath+'/icalBuddy.1': os.path.join(install_prefix, 'share/man/man1'), 94 | thispath+'/icalBuddyConfig.1': os.path.join(install_prefix, 'share/man/man1'), 95 | thispath+'/icalBuddyLocalization.1': os.path.join(install_prefix, 'share/man/man1'), 96 | } 97 | 98 | files_missing = False 99 | for sourcepath, targetpath in files_to_install.items(): 100 | if not os.path.exists(sourcepath): 101 | files_missing = True 102 | print red('Can not find file: ')+cyan(sourcepath) 103 | 104 | if files_missing: 105 | print 'Make sure you\'re running this script from the distribution' 106 | print 'folder where the above mentioned files are present.' 107 | exit_status = STATUS_ERROR 108 | sys.exit() 109 | 110 | print '=================================' 111 | print 112 | print 'This script will '+green('install')+' icalBuddy and related files:' 113 | print 114 | 115 | if existing_prefix != None and install_prefix == existing_prefix: 116 | print yellow('(icalBuddy installation found in:') 117 | print green(' '+existing_prefix) 118 | print yellow(' -- using same path for updating:)') 119 | print 120 | 121 | for sourcepath, targetpath in files_to_install.items(): 122 | filename = os.path.basename(sourcepath) 123 | print cyan(os.path.join(targetpath, filename)) 124 | 125 | if not install_prefix.startswith(homedir): 126 | print 127 | print yellow('We might need administrator privileges to install to') 128 | print yellow('this location so please enter your password if prompted.') 129 | 130 | print 131 | print 'Input '+green('y')+' to continue installing, '+yellow('c') 132 | print 'to change the installation path or '+red('q')+' to quit.' 133 | r = '' 134 | while (r not in ['y','c','q']): 135 | r = raw_input('['+green('y')+'/'+yellow('c')+'/'+red('q')+']: ').lower() 136 | 137 | if r == 'q': 138 | sys.exit(STATUS_USER_CANCEL) 139 | elif r == 'c': 140 | print 141 | print 'Input new installation prefix:' 142 | install_prefix = raw_input(': ') 143 | continue 144 | 145 | 146 | # copy files over 147 | need_sudo = False 148 | for sourcepath, targetpath in files_to_install.items(): 149 | filename = os.path.basename(sourcepath) 150 | print green('- ')+'Copying '+cyan(filename)+' to '+cyan(targetpath) 151 | 152 | if not need_sudo: 153 | try: 154 | try: 155 | os.makedirs(targetpath) 156 | except OSError, (errnum, strerror): 157 | if errnum == errno.EEXIST: pass # path exists 158 | else: raise 159 | shutil.copy(sourcepath, targetpath) 160 | print green(' copied.') 161 | except IOError, (errnum, strerror): 162 | if errnum == errno.EACCES: # permission denied 163 | need_sudo = True 164 | elif errnum == errno.ENOENT: # no such file/directory 165 | need_sudo = True 166 | else: 167 | raise 168 | except OSError, (errnum, strerror): 169 | if errnum == errno.EACCES: # permission denied 170 | need_sudo = True 171 | elif errnum == errno.ENOENT: # no such file/directory 172 | need_sudo = True 173 | else: 174 | raise 175 | except: 176 | raise 177 | 178 | if need_sudo: 179 | e_filename = filename.replace('\\', '\\\\').replace("'", "\\'") 180 | e_src_filepath = sourcepath.replace('\\', '\\\\').replace("'", "\\'") 181 | e_dest_dirpath = targetpath.replace('\\', '\\\\').replace("'", "\\'") 182 | e_dest_filepath = os.path.join(targetpath,filename).replace('\\', '\\\\').replace("'", "\\'") 183 | 184 | ret = os.system("sudo mkdir -p '"+e_dest_dirpath+"'") 185 | exit_status = (ret >> 8) & 0xFF 186 | if exit_status > 0: 187 | print red(' error: mkdir exit status '+str(exit_status)) 188 | exit_status = STATUS_ERROR 189 | 190 | ret = os.system("sudo cp -p '"+e_src_filepath+"' '"+e_dest_filepath+"'") 191 | exit_status = (ret >> 8) & 0xFF 192 | if exit_status == 0: print green(' copied.') 193 | else: 194 | print red(' error: cp exit status '+str(exit_status)) 195 | exit_status = STATUS_ERROR 196 | 197 | installed = True 198 | 199 | except KeyboardInterrupt: 200 | exit_status = STATUS_OK 201 | print 202 | except SystemExit: 203 | pass 204 | except: 205 | print red('Exception: '+str(sys.exc_info()[0])) 206 | raise 207 | exit_status = STATUS_ERROR 208 | 209 | if exit_status == STATUS_ERROR: 210 | print 211 | print red('There were errors in the installation.') 212 | print red('icalBuddy may not have been installed correctly.') 213 | print 214 | elif installed and exit_status == STATUS_OK: 215 | print 216 | print green('icalBuddy has successfully been installed.') 217 | print 218 | 219 | sys.exit(exit_status) 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | -------------------------------------------------------------------------------- /examples/generateExamplesHTML.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import types 6 | import plistlib 7 | from subprocess import Popen, PIPE, STDOUT 8 | 9 | 10 | def runInShell(cmd): 11 | o = os.popen(cmd, 'r') 12 | return o.read() 13 | 14 | def getFileContents(path): 15 | f = open(path,'r') 16 | s = f.read().strip("\n").strip() 17 | f.close() 18 | return s 19 | 20 | 21 | commandOutputsPlistPath = 'exampleCommandOutputs.plist' 22 | configFilePath = 'exampleConfig.plist' 23 | 24 | commandOutputs = plistlib.readPlist(commandOutputsPlistPath) 25 | 26 | default_code_font_size = 11 27 | default_code_font_family = 'Courier New' 28 | default_code_whitespace = 'pre-wrap' 29 | 30 | 31 | print "" 32 | print "" 33 | print "icalBuddy Examples" 34 | print "" 35 | print "" 43 | print "
" 44 | 45 | md = getFileContents('examples.markdown') 46 | lines = md.splitlines(True) 47 | 48 | formatMarker = u'••f' 49 | cmdMarker = u'•••' 50 | clearMarker = u'•----' 51 | tocMarker = u'¶¶¶ TOC ¶¶¶' 52 | 53 | formattingDict = None 54 | 55 | s = u'' 56 | for a_line in lines: 57 | line = unicode(a_line, 'utf-8') 58 | if line.strip().startswith(cmdMarker): 59 | cmdToShow = line.strip()[len(cmdMarker):].strip() 60 | if cmdToShow.startswith('icalBuddy'): 61 | cmdToShow = cmdToShow.replace('icalBuddy', '/usr/local/bin/icalBuddy') 62 | 63 | cmdToRun = cmdToShow.replace('/icalBuddy', '/icalBuddy -cf "'+configFilePath+'"') 64 | cmdToRun = cmdToRun.replace('\\', '\\\\') 65 | cmdToRun = cmdToRun.replace('"', '\\"') 66 | 67 | s += '
'
 68 | 		s += cmdToShow
 69 | 		s += '
\n\n' 70 | 71 | s += '\n' 72 | 73 | cmdOutput = commandOutputs[cmdToShow] 74 | #cmdOutput = runInShell('./cmdStdoutToHTML "'+cmdToRun+'"') 75 | cmdOutput = cmdOutput.replace('ExampleCal-', '') 76 | 77 | s += cmdOutput+'\n' 78 | s += '\n' 79 | 80 | s += '\n' 81 | 82 | if (formattingDict != None): 83 | s += '\n' 84 | s += '' 85 | s += ' \n' 86 | for key, value in formattingDict.items(): 87 | s += '\n' 88 | s += '
Values for config file formatting section
'+key+''+value.replace('ExampleCal-', '')+'
' 89 | formattingDict = None 90 | 91 | continue 92 | elif line.strip().startswith(formatMarker): 93 | if (formattingDict == None): formattingDict = {} 94 | formatSpec = line.strip()[len(formatMarker):].split('=') 95 | formattingDict[formatSpec[0].strip()] = formatSpec[1].strip() 96 | continue 97 | elif line.strip().startswith(clearMarker): 98 | s += '
' 99 | continue 100 | s += line 101 | 102 | 103 | p = Popen(['../utils/discount', '-T', '-f', '+toc', '-f', '-pants'], stdin=PIPE, stdout=PIPE, stderr=PIPE) 104 | p_out, p_err = p.communicate(input=s.encode('utf-8')) 105 | 106 | html = p_out 107 | 108 | # move table of contents into correct spot 109 | toc = '' 110 | gotTOC = False 111 | s = '' 112 | html_lines = html.splitlines(True) 113 | for a_line in html_lines: 114 | line = unicode(a_line, 'utf-8') 115 | if not gotTOC: 116 | if line.strip().find('icalBuddy Usage Examples') != -1: 117 | gotTOC = True 118 | else: 119 | toc += line 120 | continue 121 | if line.strip().find(tocMarker) != -1: 122 | s += '

Table of Contents

\n' 123 | s += '
\n' 124 | s += toc 125 | s += '
\n' 126 | continue 127 | s += line 128 | 129 | print s.encode('utf-8') 130 | 131 | print "
" # /main 132 | 133 | font_list = getFileContents('font-list.txt') 134 | fonts = font_list.splitlines() 135 | fontJSArr = 'var defaultFontNameArr = [' 136 | quotedFonts = [] 137 | for font in fonts: 138 | quotedFonts.append('"'+font+'"'); 139 | 140 | fontJSArr += ','.join(quotedFonts) 141 | fontJSArr += '];\n' 142 | 143 | print """ 144 | 145 | 196 | 197 |
198 |

You can change the look of all the output examples on this page by changing these values:

199 |
200 |
    201 |
  • Font Family: 202 | 204 |
  • 205 |
  • Font Size: 206 | px 207 | 208 | 209 |
  • 210 |
  • Wrap Lines: 211 | 212 |
  • 213 |
214 | 215 |
216 |
217 | 218 | 219 | 220 | 221 | 222 | """ 223 | 224 | print "" 225 | 226 | 227 | -------------------------------------------------------------------------------- /HGUtils.m: -------------------------------------------------------------------------------- 1 | // Misc utility functions 2 | // 3 | // http://hasseg.org/ 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2010 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import "HGUtils.h" 31 | 32 | 33 | 34 | NSError *hgInternalError(NSInteger code, NSString *description) 35 | { 36 | return [NSError 37 | errorWithDomain:kHGInternalErrorDomain 38 | code:code 39 | userInfo:[NSDictionary 40 | dictionaryWithObject:description 41 | forKey:NSLocalizedDescriptionKey 42 | ] 43 | ]; 44 | } 45 | 46 | 47 | // convenience function: concatenates strings (yes, I hate the 48 | // verbosity of -stringByAppendingString:.) 49 | // NOTE: MUST SEND nil AS THE LAST ARGUMENT 50 | NSString *strConcat(NSString *firstStr, ...) 51 | { 52 | if (!firstStr) 53 | return nil; 54 | 55 | va_list argList; 56 | NSMutableString *retVal = [firstStr mutableCopy]; 57 | NSString *str; 58 | va_start(argList, firstStr); 59 | while((str = va_arg(argList, NSString*))) 60 | [retVal appendString:str]; 61 | va_end(argList); 62 | return retVal; 63 | } 64 | 65 | NSString *escapeDoubleQuotes(NSString *str) 66 | { 67 | return [str stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; 68 | } 69 | 70 | NSString *translateEscapeSequences(NSString *str) 71 | { 72 | if (str == nil) 73 | return nil; 74 | 75 | NSMutableString *ms = [NSMutableString stringWithString:str]; 76 | [ms replaceOccurrencesOfString:@"\\n" withString:@"\n" options:NSLiteralSearch range:NSMakeRange(0,[ms length])]; 77 | [ms replaceOccurrencesOfString:@"\\t" withString:@"\t" options:NSLiteralSearch range:NSMakeRange(0,[ms length])]; 78 | [ms replaceOccurrencesOfString:@"\\e" withString:@"\e" options:NSLiteralSearch range:NSMakeRange(0,[ms length])]; 79 | return ms; 80 | } 81 | 82 | 83 | NSMutableAttributedString *mutableAttrStrWithAttrs(NSString *string, NSDictionary *attrs) 84 | { 85 | return [[[NSMutableAttributedString alloc] initWithString:string attributes:attrs] autorelease]; 86 | } 87 | 88 | // replaces all occurrences of searchStr in str with replaceStr 89 | void replaceInMutableAttrStr(NSMutableAttributedString *str, NSString *searchStr, NSAttributedString *replaceStr) 90 | { 91 | if (str == nil || searchStr == nil || replaceStr == nil) 92 | return; 93 | 94 | NSUInteger replaceStrLength = [replaceStr length]; 95 | NSString *strRegularString = [str string]; 96 | NSRange searchRange = NSMakeRange(0, [strRegularString length]); 97 | NSRange foundRange; 98 | do 99 | { 100 | foundRange = [strRegularString rangeOfString:searchStr options:NSLiteralSearch range:searchRange]; 101 | if (foundRange.location != NSNotFound) 102 | { 103 | [str replaceCharactersInRange:foundRange withAttributedString:replaceStr]; 104 | 105 | strRegularString = [str string]; 106 | searchRange.location = foundRange.location + replaceStrLength; 107 | searchRange.length = [strRegularString length] - searchRange.location; 108 | } 109 | } 110 | while (foundRange.location != NSNotFound); 111 | } 112 | 113 | 114 | 115 | 116 | // create an NSSet from a comma-separated string, 117 | // trimming whitespace from around each string component 118 | NSSet *setFromCommaSeparatedStringTrimmingWhitespace(NSString *str) 119 | { 120 | if (str != nil) 121 | { 122 | NSMutableSet *set = [NSMutableSet setWithCapacity:10]; 123 | NSArray *arr = [str componentsSeparatedByString:@","]; 124 | NSString *component; 125 | for (component in arr) 126 | [set addObject:[component stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]]; 127 | return set; 128 | } 129 | return [NSSet set]; 130 | } 131 | 132 | 133 | // create an NSArray from a comma-separated string, 134 | // trimming whitespace from around each string component 135 | NSArray *arrayFromCommaSeparatedStringTrimmingWhitespace(NSString *str) 136 | { 137 | if (str != nil) 138 | { 139 | NSMutableArray *retArr = [NSMutableArray arrayWithCapacity:10]; 140 | NSArray *arr = [str componentsSeparatedByString:@","]; 141 | NSString *component; 142 | for (component in arr) 143 | [retArr addObject:[component stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]]; 144 | return retArr; 145 | } 146 | return [NSArray array]; 147 | } 148 | 149 | 150 | // create an NSArray from a string where components are 151 | // separated by an arbitrary character and this separator character 152 | // must be present as both the first and the last character 153 | // in the given string (e.g.: @"/first/second/third/") 154 | NSArray *arrayFromArbitrarilySeparatedString(NSString *str, BOOL aTranslateEscapeSequences, NSError **error) 155 | { 156 | if (str == nil) 157 | { 158 | if (error != NULL) 159 | *error = hgInternalError(0, @"Given string is null"); 160 | return nil; 161 | } 162 | if ([str length] < 2) 163 | { 164 | if (error != NULL) 165 | *error = hgInternalError(0, @"Given string has less than two characters"); 166 | return nil; 167 | } 168 | 169 | NSString *separatorChar = nil; 170 | 171 | NSString *firstChar = [str substringToIndex:1]; 172 | NSString *lastChar = [str substringFromIndex:[str length]-1]; 173 | if ([firstChar isEqualToString:lastChar]) 174 | separatorChar = firstChar; 175 | else 176 | { 177 | if (error != NULL) 178 | *error = hgInternalError(0, @"Given string must start and end with the separator character"); 179 | return nil; 180 | } 181 | 182 | if (separatorChar != nil) 183 | { 184 | NSString *trimmedStr = [str substringWithRange:NSMakeRange(1,([str length]-2))]; 185 | if (aTranslateEscapeSequences) 186 | trimmedStr = translateEscapeSequences(trimmedStr); 187 | return [trimmedStr componentsSeparatedByString:separatorChar]; 188 | } 189 | 190 | return [NSArray array]; 191 | } 192 | 193 | 194 | 195 | NSUInteger countOccurrences(NSString *haystack, NSString *needle, NSStringCompareOptions options) 196 | { 197 | NSInteger count = -1; 198 | 199 | NSRange searchRange = NSMakeRange(0, [haystack length]); 200 | NSRange result; 201 | do 202 | { 203 | count++; 204 | result = [haystack rangeOfString:needle options:options range:searchRange]; 205 | if (result.location != NSNotFound) 206 | { 207 | searchRange.location = NSMaxRange(result); 208 | searchRange.length = [haystack length] - searchRange.location; 209 | } 210 | } 211 | while (result.location != NSNotFound); 212 | 213 | return count; 214 | } 215 | 216 | 217 | 218 | // returns YES if success, NO if failure 219 | BOOL moveFileToTrash(NSString *filePath) 220 | { 221 | if (filePath == nil) 222 | return NO; 223 | 224 | NSString *fileDir = [filePath stringByDeletingLastPathComponent]; 225 | NSString *fileName = [filePath lastPathComponent]; 226 | 227 | return [[NSWorkspace sharedWorkspace] 228 | performFileOperation:NSWorkspaceRecycleOperation 229 | source:fileDir 230 | destination:@"" 231 | files:[NSArray arrayWithObject:fileName] 232 | tag:nil 233 | ]; 234 | } 235 | 236 | 237 | -------------------------------------------------------------------------------- /icalBuddyLocalization.pod: -------------------------------------------------------------------------------- 1 | =head1 NAME 2 | 3 | B -- documentation for the icalBuddy localization file 4 | 5 | =head1 SYNOPSIS 6 | 7 | The icalBuddy localization file should be saved in F<~/.icalBuddyLocalization.plist> and is thus per-user. The contents of this file are expected to be a valid property list, so it's recommended that you use the Property List Editor application distributed with the OS X Developer Tools to edit it. If you want to edit this file manually, please consult the plist(5) and plutil(1) man pages. The example at the end of this man page might also be of help. 8 | 9 | =head1 DESCRIPTION 10 | 11 | =head2 Structure of the Localization File 12 | 13 | The root object of the localization file should be a dictionary. Keys in this dictionary should be localization string identifiers that uniquely identify specific strings that icalBuddy would like to display to the user (see below,) and the corresponding values should be the actual strings that will be displayed. 14 | 15 | =head2 General Considerations 16 | 17 | Some localization string identifiers require a specific substring to be present in their values, such as %d or %@, in order to specify the location of some variable, like a number or a string. See below for info on which identifiers have such requirements. If any localization string identifiers are missing in the localization file, icalBuddy will simply display the corresponding default strings, which will be in english. 18 | 19 | =head2 Available Localization String Identifiers 20 | 21 | The following localization string identifiers may be used: 22 | 23 | =over 16 24 | 25 | =item B> 26 | 27 | The name of the "title" property of a calendar item (event or task.) 28 | 29 | =item B> 30 | 31 | The name of the "notes" property of a calendar item (event or task.) 32 | 33 | =item B> 34 | 35 | The name of the "url" property of a calendar item (event or task.) 36 | 37 | =item B> 38 | 39 | The name of the "location" property of an event. 40 | 41 | =item B> 42 | 43 | The name of the "due date" property of a task. 44 | 45 | =item B> 46 | 47 | The words used to describe the lack of a due date for a task. 48 | 49 | =item B> 50 | 51 | The name of the "priority" property of a task. 52 | 53 | =item B> 54 | 55 | The translation of the value "high" for the "priority" property of a task. 56 | 57 | =item B> 58 | 59 | The translation of the value "medium" for the "priority" property of a task. 60 | 61 | =item B> 62 | 63 | The translation of the value "low" for the "priority" property of a task. 64 | 65 | =item B> 66 | 67 | The translation of the value "none" for the "priority" property of a task. 68 | 69 | =item B> 70 | 71 | The formatting of a task priority as a title (e.g. C<%@ priority>). Must include substring %@ to specify the location of the priority value. If this cannot be used (like it cannot for e.g. french), B>, B> and B> should be defined instead. 72 | 73 | =item B> 74 | 75 | The lack of a task priority as a title (e.g. C). 76 | 77 | =item B> 78 | 79 | "Low priority" as a title. If defined, will be used instead of B>. Note that if using B> is sufficient for the language (like it is for e.g. english), this one does not need to be defined. 80 | 81 | =item B> 82 | 83 | "Medium priority" as a title. If defined, will be used instead of B>. Note that if using B> is sufficient for the language (like it is for e.g. english), this one does not need to be defined. 84 | 85 | =item B> 86 | 87 | "High priority" as a title. If defined, will be used instead of B>. Note that if using B> is sufficient for the language (like it is for e.g. english), this one does not need to be defined. 88 | 89 | =item B> 90 | 91 | The title for an event in the Birthdays calendar (e.g. C<%@'s Birthday>.) Must include substring %@ to specify the location of the person's name, and optionally also substring %i to specify the person's age (e.g. C<%@'s Birthday (age %i)>). 92 | 93 | =item B> 94 | 95 | The title for an event in the Birthdays calendar (e.g. C<%@'s Birthday>.) Must include substring %@ to specify the location of the person's name. 96 | 97 | =item B> 98 | 99 | The title for your own birthday event (e.g. "My Birthday".) 100 | 101 | =item B> 102 | 103 | The translation of "today". 104 | 105 | =item B> 106 | 107 | The translation of "tomorrow". 108 | 109 | =item B> 110 | 111 | The translation of "yesterday". 112 | 113 | =item B> 114 | 115 | The translation of "day before yesterday". 116 | 117 | =item B> 118 | 119 | The translation of "day after tomorrow". 120 | 121 | =item B> 122 | 123 | The translation of "%d days ago", where %d is a number of days (the %d must be included to specify the location of this number.) 124 | 125 | =item B> 126 | 127 | The translation of "%d days from now", where %d is a number of days (the %d must be included to specify the location of this number.) 128 | 129 | =item B> 130 | 131 | The translation of "this week". 132 | 133 | =item B> 134 | 135 | The translation of "last week". 136 | 137 | =item B> 138 | 139 | The translation of "next week". 140 | 141 | =item B> 142 | 143 | The translation of "%d weeks ago", where %d is a number of weeks (the %d must be included to specify the location of this number.) 144 | 145 | =item B> 146 | 147 | The translation of "%d weeks from now", where %d is a number of weeks (the %d must be included to specify the location of this number.) 148 | 149 | =item B> 150 | 151 | What to print between the date and the time (for example, in english: " at ".) 152 | 153 | =item B> 154 | 155 | What to print under empty sections (i.e. dates, if separating by date and showing empty dates) (for example, in english: "Nothing.") 156 | 157 | =back 158 | 159 | =head1 EXAMPLES 160 | 161 | 162 | 163 | 164 | 165 | title 166 | title 167 | location 168 | location 169 | notes 170 | notes 171 | url 172 | url 173 | dueDate 174 | due 175 | noDueDate 176 | no due date 177 | priority 178 | priority 179 | someonesBirthday 180 | %@'s Birthday (age %i) 181 | someonesBirthdayNoAge 182 | %@'s Birthday 183 | today 184 | today 185 | tomorrow 186 | tomorrow 187 | yesterday 188 | yesterday 189 | dayBeforeYesterday 190 | day before yesterday 191 | dayAfterTomorrow 192 | day after tomorrow 193 | xDaysAgo 194 | %d days ago 195 | xDaysFromNow 196 | %d days from now 197 | thisWeek 198 | this week 199 | lastWeek 200 | last week 201 | nextWeek 202 | next week 203 | xWeeksAgo 204 | %d weeks ago 205 | xWeeksFromNow 206 | %d weeks from now 207 | high 208 | high 209 | medium 210 | medium 211 | low 212 | low 213 | noPriority 214 | none 215 | priorityTitle 216 | %@ priority 217 | priorityTitleNone 218 | No priority 219 | dateTimeSeparator 220 | at 221 | 222 | 223 | 224 | =head1 SEE ALSO 225 | 226 | icalBuddy(1), plist(5), plutil(1), icalBuddyConfig(1) 227 | 228 | =head1 AUTHORS 229 | 230 | This man page has been written by Ali Rantakari (http://hasseg.org) 231 | 232 | -------------------------------------------------------------------------------- /calendarStoreMock/MockCalCalendarStore.m: -------------------------------------------------------------------------------- 1 | // icalBuddy mocked CalendarStore 2 | // 3 | // http://hasseg.org/icalBuddy 4 | // 5 | 6 | /* 7 | The MIT License 8 | 9 | Copyright (c) 2008-2011 Ali Rantakari 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #import "MockCalCalendarStore.h" 31 | #import "../HGUtils.h" 32 | #import "../HGDateFunctions.h" 33 | 34 | 35 | 36 | @implementation MockCalCalendarStore 37 | 38 | @synthesize calendarsArr; 39 | @synthesize itemsArr; 40 | 41 | - (id) init 42 | { 43 | if (!(self = [super init])) 44 | return nil; 45 | 46 | self.calendarsArr = [NSMutableArray array]; 47 | self.itemsArr = [NSMutableArray array]; 48 | 49 | return self; 50 | } 51 | 52 | - (void) dealloc 53 | { 54 | self.calendarsArr = nil; 55 | self.itemsArr = nil; 56 | [super dealloc]; 57 | } 58 | 59 | 60 | 61 | 62 | 63 | // An array of all the user's calendars, represented as CalCalendars. If the user has iCal data from a previous 64 | // version of Mac OS X, but has not launched iCal in 10.5, this will return an array of empty calendars. iCal needs 65 | // to be launched at least once in order to migrate the user's calendar data. 66 | // 67 | // If no calendar data from any version of Mac OS X exists, then this method will create and return two default 68 | // calendars, named Home and Work. 69 | - (NSArray *)calendars 70 | { 71 | return self.calendarsArr; 72 | } 73 | 74 | 75 | // The calendar associated with the specific UID. If no record with this UID exists, nil is returned. 76 | - (CalCalendar *)calendarWithUID:(NSString *)UID 77 | { 78 | // not implemented 79 | return nil; 80 | } 81 | 82 | 83 | - (BOOL)saveCalendar:(CalCalendar *)calendar error:(NSError **)error 84 | { 85 | // not implemented 86 | return NO; 87 | } 88 | - (BOOL)removeCalendar:(CalCalendar *)calendar error:(NSError **)error 89 | { 90 | // not implemented 91 | return NO; 92 | } 93 | 94 | 95 | // - (NSArray *)eventsWithPredicate:(NSPredicate *)predicate; 96 | // 97 | // This method returns an array of all the CalEvents which match the conditions described in the predicate that is 98 | // passed. At this time, eventsWithPredicate: only suppports predicates generated with one of the class methods added 99 | // to NSPredicate below. 100 | // 101 | // If the predicate passed to eventsWithPredicate: was not created with one of the class methods included in this file, 102 | // nil is returned. If nil is passed as the predicate, an exception will be raised. 103 | // 104 | // For performance reasons, this method will only return occurrences of repeating events that fall within a specific 105 | // four year timespan. If the date range between the startDate and endDate is greater than four years, then the 106 | // timespan containing recurrences is always the first four years of date range. 107 | - (NSArray *)eventsWithPredicate:(NSPredicate *)predicate 108 | { 109 | NSMutableArray *arr = [NSMutableArray array]; 110 | 111 | for (CalCalendarItem *item in self.itemsArr) 112 | { 113 | if (![item isKindOfClass:[CalEvent class]]) 114 | continue; 115 | CalEvent *event = (CalEvent *)item; 116 | if ([predicate evaluateWithObject:event]) 117 | [arr addObject:event]; 118 | } 119 | 120 | return arr; 121 | } 122 | 123 | - (CalEvent *)eventWithUID:(NSString *)uid occurrence:(NSDate *)date 124 | { 125 | // not implemented 126 | return nil; 127 | } 128 | 129 | 130 | // - (NSArray *)tasksWithPredicate:(NSPredicate *)predicate; 131 | // 132 | // This method returns an array of all the CalTasks which match the conditions described in the predicate that is 133 | // passed. At this time, tasksWithPredicate: only suppports predicates generated with one of the class methods added to 134 | // NSPredicate below. 135 | // 136 | // If the predicate passed to tasksWithPredicate: was not created with one of the class methods included in thsi file, 137 | // nil is returned. If nil is passed as the predicate, an exception will be raised. 138 | - (NSArray *)tasksWithPredicate:(NSPredicate *)predicate 139 | { 140 | NSMutableArray *arr = [NSMutableArray array]; 141 | 142 | for (CalCalendarItem *item in self.itemsArr) 143 | { 144 | if (![item isKindOfClass:[CalTask class]]) 145 | continue; 146 | CalTask *task = (CalTask *)item; 147 | if ([predicate evaluateWithObject:task]) 148 | [arr addObject:task]; 149 | } 150 | 151 | return arr; 152 | } 153 | 154 | - (CalTask *)taskWithUID:(NSString *)uid 155 | { 156 | // not implemented 157 | return nil; 158 | } 159 | 160 | 161 | - (BOOL)saveEvent:(CalEvent *)event span:(CalSpan)span error:(NSError **)error 162 | { 163 | // not implemented 164 | return NO; 165 | } 166 | - (BOOL)removeEvent:(CalEvent *)event span:(CalSpan)span error:(NSError **)error 167 | { 168 | // not implemented 169 | return NO; 170 | } 171 | 172 | 173 | - (BOOL)saveTask:(CalTask *)task error:(NSError **)error 174 | { 175 | // not implemented 176 | return NO; 177 | } 178 | - (BOOL)removeTask:(CalTask *)task error:(NSError **)error 179 | { 180 | // not implemented 181 | return NO; 182 | } 183 | 184 | 185 | // A predicate passed to eventsWithPredicate: or tasksWithPredicate: must be returned from one of these methods. 186 | 187 | + (NSPredicate *)eventPredicateWithStartDate:(NSDate *)startDate endDate:(NSDate *)endDate calendars:(NSArray *)calendars 188 | { 189 | NSPredicate *pred = [NSPredicate 190 | predicateWithFormat: 191 | @"calendar IN %@ AND (endDate >= %@ AND startDate <= %@)", 192 | calendars, startDate, endDate 193 | ]; 194 | return pred; 195 | } 196 | 197 | + (NSPredicate *)taskPredicateWithUncompletedTasks:(NSArray *)calendars 198 | { 199 | // TODO 200 | return nil; 201 | } 202 | 203 | + (NSPredicate *)taskPredicateWithUncompletedTasksDueBefore:(NSDate *)dueDate calendars:(NSArray *)calendars 204 | { 205 | // TODO 206 | return nil; 207 | } 208 | 209 | + (NSPredicate *)eventPredicateWithStartDate:(NSDate *)startDate endDate:(NSDate *)endDate UID:(NSString *)UID calendars:(NSArray *)calendars 210 | { 211 | // not implemented 212 | return nil; 213 | } 214 | 215 | + (NSPredicate *)taskPredicateWithCalendars:(NSArray *)calendars // This will return all tasks, completed and uncompleted, for a set of calendars 216 | { 217 | // not implemented 218 | return nil; 219 | } 220 | 221 | + (NSPredicate *)taskPredicateWithTasksCompletedSince:(NSDate *)completedSince calendars:(NSArray *)calendars 222 | { 223 | // not implemented 224 | return nil; 225 | } 226 | 227 | 228 | 229 | 230 | // ----------- singleton implementation: 231 | 232 | 233 | static MockCalCalendarStore *sharedInstance = NULL; 234 | 235 | // Returns an instance of the calendar store. 236 | + (MockCalCalendarStore *) defaultCalendarStore 237 | { 238 | @synchronized(self) 239 | { 240 | if (sharedInstance == nil) 241 | sharedInstance = [[MockCalCalendarStore alloc] init]; 242 | } 243 | return sharedInstance; 244 | } 245 | 246 | + (id) allocWithZone:(NSZone *)zone 247 | { 248 | @synchronized(self) 249 | { 250 | if (sharedInstance == nil) 251 | { 252 | sharedInstance = [super allocWithZone:zone]; 253 | return sharedInstance; // assignment and return on first allocation 254 | } 255 | } 256 | return nil; // on subsequent allocation attempts return nil 257 | } 258 | 259 | - (id) copyWithZone:(NSZone *)zone 260 | { 261 | return self; 262 | } 263 | 264 | - (id) retain 265 | { 266 | return self; 267 | } 268 | 269 | - (NSUInteger) retainCount 270 | { 271 | return UINT_MAX; // denotes an object that cannot be released 272 | } 273 | 274 | - (void) release 275 | { 276 | //do nothing 277 | } 278 | 279 | - (id) autorelease 280 | { 281 | return self; 282 | } 283 | 284 | 285 | 286 | 287 | 288 | @end 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | -------------------------------------------------------------------------------- /examples/cmdStdoutToHTML.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #import 5 | #import "../ANSIEscapeHelper.h" 6 | #import "../HGCLIUtils.h" 7 | 8 | 9 | ANSIEscapeHelper *ansiHelper; 10 | 11 | 12 | NSString *runTask(NSString *path, NSArray *args) 13 | { 14 | NSPipe *pipe; 15 | pipe = [NSPipe pipe]; 16 | 17 | NSTask *task; 18 | task = [[NSTask alloc] init]; 19 | [task setLaunchPath: path]; 20 | [task setArguments: args]; 21 | [task setStandardOutput: pipe]; 22 | 23 | NSFileHandle *file; 24 | file = [pipe fileHandleForReading]; 25 | 26 | [task launch]; 27 | 28 | NSData *data; 29 | data = [file readDataToEndOfFile]; 30 | 31 | NSString *string; 32 | string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]; 33 | 34 | [task release]; 35 | 36 | return [string autorelease]; 37 | } 38 | 39 | 40 | NSString *toHTMLEntities(NSString *str, BOOL minimal) 41 | { 42 | if (str == nil) 43 | return nil; 44 | 45 | // escape special chars 46 | NSString *eStr = [((NSString *)CFXMLCreateStringByEscapingEntities(kCFAllocatorDefault, (CFStringRef)str, NULL)) autorelease]; 47 | 48 | NSMutableString *ms = [NSMutableString string]; 49 | 50 | if (minimal) 51 | { 52 | // minimal replacements 53 | ms = [eStr mutableCopy]; 54 | [ms replaceOccurrencesOfString:@"\n" withString:@"
" options:NSLiteralSearch range:NSMakeRange(0,[ms length])]; 55 | } 56 | else 57 | { 58 | // deal with line indentation & newlines 59 | NSArray *lines = [eStr componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]; 60 | for (NSString *line in lines) 61 | { 62 | int i = 0; 63 | while (i < [line length] && [line characterAtIndex:i] == 32) // 32 is the space unichar 64 | { 65 | [ms appendString:@" "]; 66 | i++; 67 | } 68 | [ms appendString:[line substringFromIndex:i]]; 69 | [ms appendString:@"
"]; 70 | } 71 | 72 | // tabs 73 | [ms replaceOccurrencesOfString:@"\t" withString:@"    " options:NSLiteralSearch range:NSMakeRange(0,[ms length])]; 74 | } 75 | 76 | return ms; 77 | } 78 | 79 | 80 | NSString *cssClassNameForSGRCode(enum sgrCode aSGRCode) 81 | { 82 | if (aSGRCode == SGRCodeIntensityBold) 83 | return @"bold"; 84 | else if (aSGRCode == SGRCodeUnderlineSingle) 85 | return @"underlined"; 86 | else if (aSGRCode == SGRCodeUnderlineDouble) 87 | return @"double-underlined"; 88 | 89 | NSDictionary *colorNames = [NSDictionary dictionaryWithObjectsAndKeys: 90 | @"black", [NSNumber numberWithInt:0], 91 | @"red", [NSNumber numberWithInt:1], 92 | @"green", [NSNumber numberWithInt:2], 93 | @"yellow", [NSNumber numberWithInt:3], 94 | @"blue", [NSNumber numberWithInt:4], 95 | @"magenta", [NSNumber numberWithInt:5], 96 | @"cyan", [NSNumber numberWithInt:6], 97 | @"white", [NSNumber numberWithInt:7], 98 | nil 99 | ]; 100 | 101 | NSDictionary *colorTypes = [NSDictionary dictionaryWithObjectsAndKeys: 102 | @"fg-", [NSNumber numberWithInt:3], 103 | @"bg-", [NSNumber numberWithInt:4], 104 | @"bright-fg-", [NSNumber numberWithInt:9], 105 | @"bright-bg-", [NSNumber numberWithInt:10], 106 | nil 107 | ]; 108 | 109 | int colorTypeNum = floor(aSGRCode / 10); 110 | int colorNum = aSGRCode % 10; 111 | NSString *prefix = nil; 112 | for (NSNumber *typeKey in colorTypes) 113 | { 114 | if ([typeKey intValue] != colorTypeNum) 115 | continue; 116 | prefix = [colorTypes objectForKey:typeKey]; 117 | break; 118 | } 119 | NSString *colorName = nil; 120 | for (NSNumber *colorKey in colorNames) 121 | { 122 | if ([colorKey intValue] != colorNum) 123 | continue; 124 | colorName = [colorNames objectForKey:colorKey]; 125 | break; 126 | } 127 | 128 | if (prefix != nil && colorName != nil) 129 | return strConcat(prefix, colorName, nil); 130 | 131 | return nil; 132 | } 133 | 134 | 135 | 136 | NSString *htmlFromAttributedString(NSAttributedString *aAttributedString) 137 | { 138 | NSString *cleanString = [aAttributedString string]; 139 | NSMutableString* retString = [NSMutableString string]; 140 | 141 | NSRange effectiveRange; 142 | NSRange limitRange = NSMakeRange(0, [aAttributedString length]); 143 | NSDictionary *attrs = nil; 144 | 145 | while (limitRange.length > 0) 146 | { 147 | // get attributes at current location + span for which they stay constant 148 | attrs = [aAttributedString 149 | attributesAtIndex:limitRange.location 150 | longestEffectiveRange:&effectiveRange 151 | inRange:limitRange 152 | ]; 153 | 154 | // determine CSS class names for these attributes 155 | NSMutableArray *classNames = [NSMutableArray array]; 156 | 157 | for (NSString *attrName in attrs) 158 | { 159 | id attrValue = [attrs valueForKey:attrName]; 160 | enum sgrCode thisSGRCode = SGRCodeNoneOrInvalid; 161 | 162 | if ([attrName isEqualToString:NSForegroundColorAttributeName]) 163 | { 164 | if ([attrValue isEqual:ansiHelper.defaultStringColor]) 165 | continue; 166 | thisSGRCode = [ansiHelper closestSGRCodeForColor:attrValue isForegroundColor:YES]; 167 | } 168 | else if ([attrName isEqualToString:NSBackgroundColorAttributeName]) 169 | { 170 | thisSGRCode = [ansiHelper closestSGRCodeForColor:attrValue isForegroundColor:NO]; 171 | } 172 | else if ([attrName isEqualToString:NSFontAttributeName]) 173 | { 174 | // we currently only use NSFontAttributeName for bolding so 175 | // here we assume that the formatting "type" in ANSI SGR 176 | // terms is indeed intensity 177 | thisSGRCode = ([[NSFontManager sharedFontManager] weightOfFont:attrValue] >= kBoldFontMinWeight) 178 | ? SGRCodeIntensityBold : SGRCodeIntensityNormal; 179 | } 180 | else if ([attrName isEqualToString:NSUnderlineStyleAttributeName]) 181 | { 182 | if ([attrValue intValue] == NSUnderlineStyleSingle) 183 | thisSGRCode = SGRCodeUnderlineSingle; 184 | else if ([attrValue intValue] == NSUnderlineStyleDouble) 185 | thisSGRCode = SGRCodeUnderlineDouble; 186 | else 187 | thisSGRCode = SGRCodeUnderlineNone; 188 | } 189 | 190 | NSString *className = cssClassNameForSGRCode(thisSGRCode); 191 | if (className == nil) 192 | continue; 193 | [classNames addObject:className]; 194 | } 195 | 196 | // append the text within our span into the string we're building, 197 | // inside a span tag with the CSS class names we have 198 | if ([classNames count] > 0) 199 | { 200 | [retString appendString:@""]; 203 | } 204 | [retString appendString:[cleanString substringWithRange:effectiveRange]]; 205 | if ([classNames count] > 0) 206 | { 207 | [retString appendString:@""]; 208 | } 209 | 210 | 211 | limitRange = NSMakeRange(NSMaxRange(effectiveRange), 212 | NSMaxRange(limitRange) - NSMaxRange(effectiveRange)); 213 | } 214 | 215 | return retString; 216 | } 217 | 218 | 219 | 220 | int main(int argc, char *argv[]) 221 | { 222 | NSAutoreleasePool *autoReleasePool = [[NSAutoreleasePool alloc] init]; 223 | 224 | ansiHelper = [[[ANSIEscapeHelper alloc] init] autorelease]; 225 | 226 | NSString *arg_outputFilePath = nil; 227 | NSString *arg_commandToRun = nil; 228 | BOOL arg_readCommandsFromSTDIN = YES; 229 | BOOL arg_replaceMinimalHTMLEntities = YES; 230 | 231 | for (int i = 1; i < argc; i++) 232 | { 233 | if (strcmp(argv[i], "-o") == 0) 234 | arg_outputFilePath = [NSString stringWithUTF8String:argv[i+1]]; 235 | else if (strcmp(argv[i], "-e") == 0) 236 | arg_replaceMinimalHTMLEntities = NO; 237 | else if (strcmp(argv[i], "-c") == 0) 238 | { 239 | arg_commandToRun = [NSString stringWithUTF8String:argv[i+1]]; 240 | arg_readCommandsFromSTDIN = NO; 241 | } 242 | } 243 | 244 | if (arg_readCommandsFromSTDIN) 245 | { 246 | NSFileHandle *stdinHandle = [NSFileHandle fileHandleWithStandardInput]; 247 | NSData *stdinData = [NSData dataWithData:[stdinHandle readDataToEndOfFile]]; 248 | arg_commandToRun = [[[NSString alloc] initWithData:stdinData encoding:NSUTF8StringEncoding] autorelease]; 249 | } 250 | 251 | if (arg_commandToRun != nil) 252 | arg_commandToRun = [arg_commandToRun stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 253 | 254 | if (!arg_readCommandsFromSTDIN && (arg_commandToRun == nil || [arg_commandToRun length] == 0)) 255 | { 256 | PrintfErr(@"Need command to run as an argument (-c command) or\n"); 257 | PrintfErr(@"specified line-by-line via STDIN.\n"); 258 | return 1; 259 | } 260 | 261 | NSArray *commands = [arg_commandToRun componentsSeparatedByString:@"\n"]; 262 | 263 | NSMutableDictionary *commandsAndOutputs = [NSMutableDictionary dictionaryWithCapacity:[commands count]]; 264 | 265 | for (NSString *command in commands) 266 | { 267 | NSString *output = runTask(@"/bin/bash", [NSArray arrayWithObjects: @"-c", command, nil]); 268 | output = toHTMLEntities(output, arg_replaceMinimalHTMLEntities); 269 | output = htmlFromAttributedString([ansiHelper attributedStringWithANSIEscapedString:output]); 270 | [commandsAndOutputs setObject:output forKey:command]; 271 | } 272 | 273 | if (arg_outputFilePath != nil) 274 | { 275 | [commandsAndOutputs writeToFile:arg_outputFilePath atomically:YES]; 276 | } 277 | else 278 | { 279 | for (NSString *key in commandsAndOutputs) 280 | { 281 | Print([commandsAndOutputs objectForKey:key]); 282 | } 283 | } 284 | 285 | 286 | [autoReleasePool release]; 287 | return 0; 288 | } 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # icalBuddy makefile 2 | # 3 | # Created by Ali Rantakari on 18 June, 2008 4 | # 5 | 6 | SHELL=/bin/bash 7 | 8 | CURRDATE=$(shell date +"%Y-%m-%d") 9 | APP_VERSION=$(shell ./icalBuddy -V) 10 | VERSION_ON_SERVER=$(shell curl -Ss http://hasseg.org/icalBuddy/?versioncheck=y) 11 | TEMP_DEPLOYMENT_DIR=deployment/$(APP_VERSION) 12 | TEMP_DEPLOYMENT_ZIPFILE=$(TEMP_DEPLOYMENT_DIR)/icalBuddy-v$(APP_VERSION).zip 13 | TEMP_DEPLOYMENT_MANFILE="deployment/man.html" 14 | TEMP_DEPLOYMENT_L10NMANFILE="deployment/localization-man.html" 15 | TEMP_DEPLOYMENT_CONFIGMANFILE="deployment/config-man.html" 16 | TEMP_DEPLOYMENT_FAQFILE="deployment/faq.html" 17 | FILES_TO_PACKAGE="$(TEMP_DEPLOYMENT_FAQFILE) icalBuddy icalBuddy.1 icalBuddyLocalization.1 icalBuddyConfig.1" 18 | VERSIONCHANGELOGFILELOC="$(TEMP_DEPLOYMENT_DIR)/changelog.html" 19 | GENERALCHANGELOGFILELOC="changelog.html" 20 | SCP_TARGET=$(shell cat ./deploymentScpTarget) 21 | DEPLOYMENT_INCLUDES_DIR="./deployment-files" 22 | 23 | COMPILER_GCC=gcc 24 | COMPILER_CLANG=clang 25 | COMPILER=$(COMPILER_CLANG) 26 | 27 | CC_WARN_OPTS=-Wall -Wextra -Wno-unused-parameter -Werror 28 | 29 | SOURCE_FILES=icalBuddy[ABCDEFGHIJKLMNOPQRSTUVWXYZ]*.m ANSIEscapeHelper.m HG*.m IcalBuddy*.m *+HGAdditions.m 30 | 31 | 32 | 33 | all: icalBuddy 34 | 35 | 36 | 37 | #------------------------------------------------------------------------- 38 | #------------------------------------------------------------------------- 39 | # compile the binary itself 40 | #------------------------------------------------------------------------- 41 | icalBuddy: $(SOURCE_FILES) icalBuddy.m 42 | @echo 43 | @echo ---- Compiling main app: 44 | @echo ====================================== 45 | $(COMPILER) $(ARG_DEBUG) -O3 $(CC_WARN_OPTS) -std=c99 -force_cpusubtype_ALL -mmacosx-version-min=10.5 -arch x86_64 -framework Cocoa -framework CalendarStore -framework AppKit -framework AddressBook -o $@ icalBuddy.m $(SOURCE_FILES) 46 | 47 | 48 | 49 | #------------------------------------------------------------------------- 50 | #------------------------------------------------------------------------- 51 | # compile test binary 52 | #------------------------------------------------------------------------- 53 | testIcalBuddy: $(SOURCE_FILES) icalBuddy.m calendarStoreMock/*.m 54 | @echo 55 | @echo ---- Compiling TEST version of main app: 56 | @echo ====================================== 57 | $(COMPILER) $(ARG_DEBUG) -O3 -Wall -std=c99 -force_cpusubtype_ALL -mmacosx-version-min=10.5 -arch x86_64 -DUSE_MOCKED_CALENDARSTORE -framework Cocoa -framework CalendarStore -framework AppKit -framework AddressBook -o $@ icalBuddy.m calendarStoreMock/*.m $(SOURCE_FILES) 58 | 59 | 60 | 61 | 62 | #------------------------------------------------------------------------- 63 | #------------------------------------------------------------------------- 64 | # run clang static analyzer 65 | #------------------------------------------------------------------------- 66 | analyze: 67 | @echo 68 | @echo ---- Analyzing: 69 | @echo ====================================== 70 | $(COMPILER_CLANG) --analyze icalBuddy.m $(SOURCE_FILES) 71 | 72 | 73 | 74 | 75 | 76 | #------------------------------------------------------------------------- 77 | #------------------------------------------------------------------------- 78 | # compile the test runner 79 | #------------------------------------------------------------------------- 80 | testRunner: $(SOURCE_FILES) 81 | @echo 82 | @echo ---- Compiling test runner: 83 | @echo ====================================== 84 | $(COMPILER) $(ARG_DEBUG) -O3 -Wall -std=c99 -force_cpusubtype_ALL -mmacosx-version-min=10.5 -arch x86_64 -DUSE_MOCKED_CALENDARSTORE -framework Cocoa -framework CalendarStore -framework AppKit -framework AddressBook -o $@ testRunner.m $(SOURCE_FILES) calendarStoreMock/*.m tests/unit/*.m 85 | 86 | 87 | 88 | 89 | #------------------------------------------------------------------------- 90 | #------------------------------------------------------------------------- 91 | # write usage output to text file 92 | #------------------------------------------------------------------------- 93 | usage.txt: icalBuddy 94 | @echo 95 | @echo ---- generating usage.txt: 96 | @echo ====================================== 97 | ./icalBuddy > usage.txt 98 | 99 | 100 | #------------------------------------------------------------------------- 101 | #------------------------------------------------------------------------- 102 | # generate main man page from POD syntax file 103 | #------------------------------------------------------------------------- 104 | icalBuddy.1: icalBuddy.pod 105 | @echo 106 | @echo ---- Generating manpage from POD file: 107 | @echo ====================================== 108 | pod2man --section=1 --release="$(APP_VERSION)" --center="icalBuddy" --date="$(CURRDATE)" icalBuddy.pod > icalBuddy.1 109 | 110 | #------------------------------------------------------------------------- 111 | #------------------------------------------------------------------------- 112 | # generate configuration man page from POD syntax file 113 | #------------------------------------------------------------------------- 114 | icalBuddyConfig.1: icalBuddyConfig.pod 115 | @echo 116 | @echo ---- Generating config manpage from POD file: 117 | @echo ====================================== 118 | pod2man --section=1 --release="$(APP_VERSION)" --center="icalBuddy configuration" --date="$(CURRDATE)" icalBuddyConfig.pod > icalBuddyConfig.1 119 | 120 | #------------------------------------------------------------------------- 121 | #------------------------------------------------------------------------- 122 | # generate localization man page from POD syntax file 123 | #------------------------------------------------------------------------- 124 | icalBuddyLocalization.1: icalBuddyLocalization.pod 125 | @echo 126 | @echo ---- Generating localization manpage from POD file: 127 | @echo ====================================== 128 | pod2man --section=1 --release="$(APP_VERSION)" --center="icalBuddy localization" --date="$(CURRDATE)" icalBuddyLocalization.pod > icalBuddyLocalization.1 129 | 130 | 131 | 132 | 133 | #------------------------------------------------------------------------- 134 | #------------------------------------------------------------------------- 135 | # generate FAQ HTML 136 | #------------------------------------------------------------------------- 137 | deployment/faq.html: faq.markdown faq-style.css 138 | @echo 139 | @echo ---- Generating HTML from FAQ: 140 | @echo ====================================== 141 | echo "icalBuddy FAQ" > $(TEMP_DEPLOYMENT_FAQFILE) 142 | echo "" >> $(TEMP_DEPLOYMENT_FAQFILE) 143 | echo "" >> $(TEMP_DEPLOYMENT_FAQFILE) 146 | echo "
" >> $(TEMP_DEPLOYMENT_FAQFILE) 147 | echo "

icalBuddy FAQ


Table Of Contents

" >> $(TEMP_DEPLOYMENT_FAQFILE) 148 | utils/discount -T -f +toc faq.markdown >> $(TEMP_DEPLOYMENT_FAQFILE) 149 | echo "
" >> $(TEMP_DEPLOYMENT_FAQFILE) 150 | 151 | 152 | 153 | #------------------------------------------------------------------------- 154 | #------------------------------------------------------------------------- 155 | # generate documentation 156 | #------------------------------------------------------------------------- 157 | docs: icalBuddy.1 deployment/faq.html icalBuddyLocalization.1 icalBuddyConfig.1 usage.txt 158 | @echo 159 | @echo ---- Generating HTML from manpages: 160 | @echo ====================================== 161 | utils/manserver.pl icalBuddy.1 | sed -e 's///' > $(TEMP_DEPLOYMENT_MANFILE) 162 | utils/manserver.pl icalBuddyLocalization.1 | sed -e 's///' > $(TEMP_DEPLOYMENT_L10NMANFILE) 163 | utils/manserver.pl icalBuddyConfig.1 | sed -e 's///' > $(TEMP_DEPLOYMENT_CONFIGMANFILE) 164 | 165 | 166 | 167 | #------------------------------------------------------------------------- 168 | #------------------------------------------------------------------------- 169 | # make release package (prepare for deployment) 170 | #------------------------------------------------------------------------- 171 | package: icalBuddy docs 172 | @echo 173 | @echo ---- Preparing for deployment: 174 | @echo ====================================== 175 | 176 | # create zip archive 177 | mkdir -p $(TEMP_DEPLOYMENT_DIR) 178 | echo "-D -j $(TEMP_DEPLOYMENT_ZIPFILE) $(FILES_TO_PACKAGE)" | xargs zip 179 | cd "$(DEPLOYMENT_INCLUDES_DIR)"; echo "-g -x *.DS_Store -R ../$(TEMP_DEPLOYMENT_ZIPFILE) *" | xargs zip 180 | 181 | # if changelog doesn't already exist in the deployment dir 182 | # for this version, get 'general' changelog file from root if 183 | # one exists, and if not, create an empty changelog file 184 | @( if [ ! -e $(VERSIONCHANGELOGFILELOC) ];then\ 185 | if [ -e $(GENERALCHANGELOGFILELOC) ];then\ 186 | cp $(GENERALCHANGELOGFILELOC) $(VERSIONCHANGELOGFILELOC);\ 187 | echo "Copied existing changelog.html from project root into deployment dir - opening it for editing";\ 188 | else\ 189 | echo -e "
    \n
  • \n
\n" > $(VERSIONCHANGELOGFILELOC);\ 190 | echo "Created new empty changelog.html into deployment dir - opening it for editing";\ 191 | fi; \ 192 | else\ 193 | echo "changelog.html exists for $(APP_VERSION) - opening it for editing";\ 194 | fi ) 195 | @open -a Fraise $(VERSIONCHANGELOGFILELOC) 196 | 197 | 198 | 199 | 200 | #------------------------------------------------------------------------- 201 | #------------------------------------------------------------------------- 202 | # deploy to server 203 | #------------------------------------------------------------------------- 204 | deploy: package 205 | @echo 206 | @echo ---- Deploying to server: 207 | @echo ====================================== 208 | 209 | @echo "Checking latest version number vs. current version number..." 210 | @( if [ "$(VERSION_ON_SERVER)" != "$(APP_VERSION)" ];then\ 211 | echo "Latest version on server is $(VERSION_ON_SERVER). Uploading $(APP_VERSION).";\ 212 | else\ 213 | echo "NOTE: Current version exists on server: ($(APP_VERSION)).";\ 214 | fi;\ 215 | echo "Press enter to continue uploading to server or Ctrl-C to cancel.";\ 216 | read INPUTSTR;\ 217 | scp -r $(TEMP_DEPLOYMENT_DIR) $(TEMP_DEPLOYMENT_MANFILE) $(TEMP_DEPLOYMENT_L10NMANFILE) $(TEMP_DEPLOYMENT_CONFIGMANFILE) $(TEMP_DEPLOYMENT_FAQFILE) usage.txt $(SCP_TARGET); ) 218 | 219 | 220 | 221 | 222 | #------------------------------------------------------------------------- 223 | #------------------------------------------------------------------------- 224 | clean: 225 | @echo 226 | @echo ---- Cleaning up: 227 | @echo ====================================== 228 | -rm -Rf icalBuddy 229 | -rm -Rf icalBuddy.1 230 | -rm -Rf testIcalBuddy 231 | -rm -Rf testRunner 232 | -rm -Rf icalBuddy*.plist 233 | -rm -Rf IcalBuddy*.plist 234 | -rm -Rf HG*.plist 235 | -rm -Rf ANSIEscape*.plist 236 | -rm -Rf icalBuddyConfig.1 237 | -rm -Rf icalBuddyLocalization.1 238 | -rm -Rf deployment/* 239 | 240 | 241 | 242 | --------------------------------------------------------------------------------