The Omni Group Forums

The Omni Group Forums (http://forums.omnigroup.com/index.php)
-   OmniFocus 1 for Mac (http://forums.omnigroup.com/forumdisplay.php?f=38)
-   -   FAQ: Enabling App-Store versions to use existing scripts and hints (http://forums.omnigroup.com/showthread.php?t=21496)

RobTrew 2011-06-29 03:09 AM

FAQ: Enabling App-Store copies to use existing scripts and hints
 
There may be as many as 400 posts on these OmniFocus forums which contain technical tips or scripts which would work for directly-purchased copies of OmniFocus, but would not work on copies purchased through the Mac App Store.

[[I]Estimate based on results from the 'advanced search' dialogue this morning: keyword:"com.omnigroup" forum: OmniFocus and child forums - show results as:post (447 posts, in over 280 different threads)[/I]]

There are also various OmniFocus scripts hosted on other sites which Mac App Store copies are similarly unable to run.

I suspect that neither Omni nor the user community can afford to spend the northern summer going through all these scripts and technical hints to edit even just the most useful ones into a shape that MAS-purchased copies can run.

In other words, first-aid for puzzled or disappointed users of app-store copies will mainly have to be DIY.

It may, therefore, be helpful to summarize the problem and the fixes.

The problem boils down to:[INDENT][I]com.omnigroup.Omnifocus[/I][/INDENT]vs[INDENT][I]com.omnigroup.OmniFocus.MacAppStore[/I][/INDENT]
[For perfectly understandable reasons of internal house-keeping, Omni, unlike most other companies who sell through the Mac App Store, have [URL="http://forums.omnigroup.com/showthread.php?t=21470"]chosen to give the App Store version a different 'bundle name'[/URL]. Unfortunately, while this doesn't affect the performance of the software itself, it does prevent it from running a number of the useful scripts and command line hints that are published on this board and elsewhere]

[B]Applescripts[/B][INDENT]If you find that your Mac App Store copy of OmniFocus can not run an OmniFocus Applescript, you may need to edit:
[INDENT][I]application id "com.omnigroup.omnifocus"[/I][/INDENT]

to any one of the following (it doesn't really matter which)
[INDENT][I]application id "OFOC"
application "OmniFocus"
application id "com.omnigroup.omnifocus.macappstore"[/I]
[/INDENT](NB the middle option doesn't use the "id" keyword)

If you are still getting messages about missing databases, you may need to edit:
[INDENT][I]~/Library/Caches/com.omnigroup.OmniFocus/OmniFocusDatabase2[/I][/INDENT]to [INDENT][I]~/Library/Caches/com.omnigroup.OmniFocus.MacAppStore/OmniFocusDatabase2[/I][/INDENT]
We should be able to find the correct path for the database file with more general code along the lines of:

[CODE]property pTitle : "Coding for variant bundle identifiers"
property pstrDBPath : "$HOME/Library/Caches/com.omnigroup.OmniFocus/OmniFocusDatabase2"

on run
if not CacheFound() then return

display dialog (do shell script "sqlite3 \"" & pstrDBPath &
"\" 'select count(*) from task where projectInfo is null and childrenCount = 0'") &
" tasks" buttons {"OK"} default button 1 with title pTitle
end run

on CacheFound()
if (do shell script "test -e \"" & pstrDBPath & "\"; echo $?") ≠ "0" then
try
tell application "Finder" to tell (application file id "OFOC") to
set pstrDBPath to "$HOME/Library/Caches/" & its id & "/OmniFocusDatabase2"
on error
error "OmniFocus not installed..."
return false
end try
if (do shell script "test -e \"" & pstrDBPath & "\"; echo $?") ≠ "0" then
error "OmniFocus cache not found at " & return & pstrDBPath
return false
end if
end if
return true
end CacheFound[/CODE]


Note that you can also derive the currently installed bundle variant (in exchange for the more stable and ancestral 4 letter creator code) for other bifurcating Omni products, like OmniGraffle, OmniPlan, OmniOutliner, and OmniGraphSketcher:
[CODE]property pTitle : "Bundle variants of installed Omni apps"
property plstName : {"OmniFocus", "OmniGraffle", "OmniPlan", "OmniOutliner", "OmniGraphSketcher"}
property plstCode : {"OFOC", "OGfl", "OPla", "OOut", "RSGS"}

set str to ""
tell application "Finder"
repeat with i from 1 to length of plstCode
try
set str to (str & id of application file id (item i of plstCode) as string) & return
on error
set str to str & item i of plstName & " not installed" & return
end try
end repeat

if button returned of (display dialog str buttons {"Esc", "Copy"} default button 2 with title pTitle) ≠ "Esc" then
set the clipboard to str
end if
end tell[/CODE]

[I][NOTE: the advantage of including the keyword [B]file[/B] before [B]id[/B] in the expressions above is that it avoids forcing the application to launch if it is not currently running. If the application is already running, or forcing it to launch is not a problem, then execution will be marginally faster if [B]file [/B] is omitted][/I]
[/INDENT]
[B]Command Lines[/B]
[INDENT]Changing the path of the database file, as above, will also be the solution if you are having no luck with a tip for a Terminal command line that includes the keyword [I][URL="http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/sqlite3.1.html"]sqlite3[/URL][/I]

For example, to get a total count of tasks, (fine-tuning [URL="http://forums.omnigroup.com/showpost.php?p=41107&postcount=3"]Ken Case's tip[/URL], to exclude the projects and action groups from the count) :
[CODE]sqlite3 ~/Library/Caches/com.omnigroup.OmniFocus/OmniFocusDatabase2 'select count(*) from task where projectInfo is null and childrenCount=0'[/CODE]
would simply become:
[CODE]sqlite3 ~/Library/Caches/com.omnigroup.OmniFocus.[B]MacAppStore[/B]/OmniFocusDatabase2 'select count(*) from task where projectInfo is null and childrenCount=0'[/CODE]

Or, more generally, with two command lines:
[CODE]OFOC=$(osascript -e 'tell application "Finder" to get id of application file id "OFOC"')
sqlite3 ~/Library/Caches/$OFOC/OmniFocusDatabase2 'select count(*) from task where projectInfo is null and childrenCount=0'[/CODE]



Finally, if you are having no luck with a tip or hint that involves a command line starting with something like:
[INDENT][I][URL="http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/defaults.1.html"]defaults[/URL] write[/I][/INDENT]or[INDENT][I][URL="http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/defaults.1.html"]defaults[/URL] delete[/I][/INDENT]
then, again, you need to change the domain from "com.omnigroup.Omnifocus" to "com.omnigroup.Omnifocus.MacAppStore"

To allow for uncertainty about which version is installed on a machine, and to defend against yet more proliferation of bundle variants, we would have to retreat from the elegance and brevity of Ken Case's [URL="http://twitter.com/#!/kcase/status/76012475602051073"]tweetable command line[/URL] of June 1 2011, to the relative verbosity and inconvenience of a more circumspect applescript:

[CODE]DefaultsWrite("OFOC", "AppleHighlightColor", "1.0 0.0 0.0")

on DefaultsWrite(strCreator, strKey, strValue)
tell application "Finder"
try
return do shell script ("defaults write " & id of application file id strCreator &
space & strKey & space & quoted form of strValue)
on error
return "Could not find an application with Creator code " & strCreator
end try
end tell
end DefaultsWrite[/CODE]

Try tweeting that ...

In the uncertain world of .MacAppStore and other variant bundle identifiers, restoring a default setting with [I]defaults delete[/I] becomes equally verbose:

[CODE]DefaultsDelete("OFOC", "AppleHighlightColor")

on DefaultsDelete(strCreator, strKey)
tell application "Finder"
try
return do shell script ("defaults delete " & id of application file id strCreator & space & strKey)
on error strMsg number errNum
if errNum = -10814 then
tell application id "sevs"
activate
display alert "No application found with creator code " & strCreator
end tell
else
return ""
end if
end try
end tell
end DefaultsDelete[/CODE]

Probably simpler to do it in the terminal. We can get the installed bundle identifier into a variable,

[CODE]OFOC=$(osascript -e 'tell application "Finder" to get id of application file id "OFOC"')[/CODE]

and then use the variable to change settings,
[CODE]defaults write $OFOC AppleHighlightColor "1.0 0.0 0.0"[/CODE]
or restore defaults.
[CODE]defaults delete $OFOC AppleHighlightColor[/CODE]


[B]Complex installation histories[/B]

Applications can be installed to the all-user [I]/Applications[/I] folder, or the user-specific [I]~/Applications[/I] folder, or even, if history is getting little complex and messy, to both. We could even end up with different variants in different places ...

To check which .app file would actually be launched by an applescript, we can write something like:

[CODE]-- e.g.
-- OFOC OmniFocus
-- OGfl OmniGraffle
-- OOut OmniOutliner
-- DNtp DEVONthink Pro
-- Scrv Scrivener
-- etc

AppPath("OFOC")

on AppPath(strCreatorCode)
tell application "Finder" to tell (application file id strCreatorCode) to POSIX path of (its container as alias) & name
end AppPath
[/CODE]



I may have overlooked some other issues, but at least this is a start ...[/INDENT]
Good luck !

PS, a caveat:

I don't own an AppStore-bought copy myself, and thus haven't been able to test the remedies above, so to quote the immortal Dr Livesey, "look out for squalls ..."


[COLOR="White"]--[/COLOR]

RobTrew 2011-06-30 12:48 PM

As a footnote, experiment suggests than one can sniff out the difference between vanilla and curdled milk (that is, get the bundle identifier string without having to launch the app, and therefore know where to look for the cache) by using something like:

[CODE]on OFBundleID()
set strPath to "Applications/OmniFocus.app/Contents/info.plist"

tell application id "MACS"
if not (exists strPath as POSIX file) then
set strPath to ((POSIX path of (path to home folder)) & strPath)
if not (exists strPath as POSIX file) then
display alert "OmniFocus.app not found"
return ""
end if
end if
end tell

tell application id "sevs" to return value of property list item "CFBundleIdentifier" of contents of property list file strPath
end OFBundleID[/CODE]

RobTrew 2011-06-30 01:08 PM

Or, more simply,

[CODE]tell application "Finder"
exists application file id "com.omnigroup.OmniFocus"
end tell[/CODE]

etc ...

(Thanks to Ken Case - who has been pursuing some interesting idioms for coping with a dual bundle ecology - for spotting this and sharing it. It allows for for an improved [I]GetCachePath()[/I] function, as amended in post 1 above)

[COLOR="White"]--[/COLOR]

bpwhistler 2012-04-16 07:31 PM

RobTrew...thanks for the complete description. I'm still having problems if you would be willing to take a look! :)

Here's my script
[CODE](*
Waiting For Mails to OmniFocus Script
by simplicityisbliss.com, Sven Fechner
MailTags project and due date compatibility added by Scott Morrison, Indev Software

Based on an Outbox Rule (Mail Act-On) in Mail.app this script adds specific messages
to the OmniFocus Inbox with the waiting for context

MailTags is required to automatically set the project and the due date.

Mail Act-On (www.indev.ca) is required to define the Outbox Rule to only
create tasks for those outgoing emails that are to be tracked in OmniFocus

A sample Outbox rule may be
if MailTags Tickle Date is After 0 days today
Run Apple Script: [ThisAppleScript]


The script uses Growl from the App Store for feedback notification if it is installed and running

*)


--!! EDIT THE PROPERTIES BELOW TO MEET YOUR NEEDS !!--

-- Do you want the actualy mail body to be added to the notes section of the OmniFocus task?
-- Set to 'true' is or 'false' if no
property mailBody : true

-- Text between mail recipient (the person you are waiting for to come back) and the email subject
property MidFix : "to follow up re:"

-- Name of your Waiting For context in OmniFocus
property myWFContext : "Waiting for"

-- Default start time
property timeStart : "5:00:00 AM"

-- Default due time
property timeDue : "11:59:00 PM"

-- Default start to due date interval, in days
property dateInterval : "3"

-- !! STOP EDITING HERE IF NOT FAMILAR WITH APPLESCRIPT !! --

--Configuration for Growl messages
property GrowlRun : true
property scriptName : "Waiting For Mails to OmniFocus"
property notifySuccess : "Success Notification"
property notifyFail : "Failed Notification"
property titleSuccess : "Waiting For Mail added"
property titleFail : "Waiting For Mail to OmniFocus FAILED"
property txtSuccess : " added to OmniFocus successfully"
property txtFail : " to OmniFocus to add successfully"
property txtIcon : "OmniFocus"

on perform_mail_action(theData)
--Check if Growl is running
tell application "System Events" to set GrowlRun to (count of (every process whose name is "Growl")) > 0

--Setup Growl
if GrowlRun then tell application "Growl" to register as application scriptName all notifications {notifySuccess, notifyFail} default notifications {notifySuccess, notifyFail} icon of application txtIcon

--Get going
tell application "Mail"
set theMessages to |SelectedMessages| of theData --Extract the messages from the rule
repeat with theMessage in theMessages
set theSubject to subject of theMessage
set theRecipient to name of to recipient of theMessage
set theMessageID to urlencode(the message id of theMessage) of me
set theStartDate to ""
set theDueDate to ""

try
using terms from application "MailTagsScriptingSupport"
set theStartDate to (due date of theMessage) as date
set theStartDate to my setStartDate(theStartDate)
set theDueDate to theStartDate + dateInterval * days
set theDueDate to my setDueDate(theDueDate)
end using terms from
on error theError

end try

-- Check if there is one or more recipients
try
if (count of theRecipient) > 1 then
set theRecipientName to (item 1 of theRecipient & (ASCII character 202) & "and" & (ASCII character 202) & ((count of theRecipient) - 1) as string) & (ASCII character 202) & "more"
else
set theRecipientName to item 1 of theRecipient
end if

set theTaskTitle to theRecipientName & (ASCII character 202) & MidFix & (ASCII character 202) & theSubject
set messageURL to "Created from message://%3C" & (theMessageID) & "%3E"
set theBody to messageURL
if mailBody then set theBody to theBody & return & return & the content of theMessage

-- Add waiting for context task to OmniFocus
tell application "OmniFocus"
tell default document
set theContext to context myWFContext

if theStartDate is not "" then
set theTask to make new inbox task with properties {name:theTaskTitle, note:theBody, context:theContext, start date:theStartDate, due date:theDueDate}
else
set theTask to make new inbox task with properties {name:theTaskTitle, note:theBody, context:theContext}

end if
if myProject is not null then
set theProject to project myProject
move theTask to end of tasks of theProject

end if
end tell
end tell

on error theError
do shell script "logger -t outboxrule 'Error : " & theError & "' "
end try

my GrowlSuccess("Mail: " & theSubject)
end repeat
end tell

end perform_mail_action

on GrowlSuccess(theMessage)
if GrowlRun then tell application "Growl" to notify with name notifySuccess title titleSuccess description theMessage & txtSuccess application name scriptName
end GrowlSuccess

on urlencode(theText)
set theTextEnc to ""
repeat with eachChar in characters of theText
set useChar to eachChar
set eachCharNum to ASCII number of eachChar
if eachCharNum = 32 then
set useChar to "+"
else if (eachCharNum ≠ 42) and (eachCharNum ≠ 95) and (eachCharNum < 45 or eachCharNum > 46) and (eachCharNum < 48 or eachCharNum > 57) and (eachCharNum < 65 or eachCharNum > 90) and (eachCharNum < 97 or eachCharNum > 122) then
set firstDig to round (eachCharNum / 16) rounding down
set secondDig to eachCharNum mod 16
if firstDig > 9 then
set aNum to firstDig + 55
set firstDig to ASCII character aNum
end if
if secondDig > 9 then
set aNum to secondDig + 55
set secondDig to ASCII character aNum
end if
set numHex to ("%" & (firstDig as string) & (secondDig as string)) as string
set useChar to numHex
end if
set theTextEnc to theTextEnc & useChar as string
end repeat
return theTextEnc
end urlencode

on setStartDate(theStartDate)
set theDate to (date string of theStartDate)
set newDate to the (date (theDate & " " & timeStart))
return newDate
end setStartDate

on setDueDate(theDueDate)
set theDate to (date string of theDueDate)
set newDate to the (date (theDate & " " & timeDue))
return newDate
end setDueDate
[/CODE]

I replaced:
[CODE]-- Add waiting for context task to OmniFocus
tell application "OmniFocus"[/CODE]

with:
[CODE]tell application id "com.omnigroup.omnifocus.macappstore"[/CODE]

My script ran well before I updated from a non-MAS version to a MAS version. It stopped as soon as I installed the MAS version. It doesn't work with the updated code either.

Any ideas or suggestions?

Thanks...Brett

RobTrew 2012-04-17 01:44 AM

It doesn't immediately look like an App store version referencing issue, because the form you are using:

[I][INDENT]tell application "OmniFocus"[/INDENT][/I]

Should work with both.

I personally tend to use:

[I][INDENT]tell application id "OFOC"[/INDENT][/I]

which also works with both. (Note that it is case-sensitive).

I don't have an App Store copy, so I can't directly test whether:

[I][INDENT]tell application id "com.OmniFocus.MacAppStore"[/INDENT][/I]
is case-sensitive.

[COLOR="White"]--[/COLOR]

RobTrew 2012-04-17 01:50 AM

[QUOTE=bpwhistler;109554]I [I]updated[/I] from a non-MAS version to a MAS version.[/QUOTE]

Not quite sure what the procedure was, but my first guess would be that this might leave a slightly messy installation, with some remaining elements of the vanilla version interacting with the running of scripts in the App Store version.


All times are GMT -8. The time now is 07:11 AM.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2020, vBulletin Solutions, Inc.