Ultimate MS Outlook Editor

matthew's picture

At my work, I'm required to use Microsoft Outlook for exchanging email with my co-workers. At home, I use Mutt on FreeBSD, and have grown to really love the lightning-fast responsiveness, immunity to virusses, and easy scriptability of this tiny text-based mail reader.

I'm going to tell you one solution, just so I can tell you another one :)

It's possible to use Mutt with Microsoft Exchange:

  • Set up IMAP on your Exchange server. This was already done here.
  • Install a copy of Cygwin, including Python.
  • Either set up Mutt to access IMAP on Exchange directly, or do what I prefer to do: download and set up offlineimap. This IMAP-to-Maildir synchronization utility is excellent.
    1. First, you need to run the "rebaseall" utility so that Python doesn't dump with traceback when you try to run offlineimap. You can't rebaseall if you're trying to do it from an rxvt window -- you need to be using the cmd-based Cygwin shell for it to finish without an error.
    2. Then you need make sure your .offlineimaprc file specifies "Curses.Blinkenlights" as the first available interface -- the TK interface, on Win32, just hangs.
  • You can't use offlineimap on a non-managed Cygwin mount. The reason is that the Maildir specification uses the ":" character, which is a big no-no in Windows-land. The solution is to use this command:
    $ mount -f -s -b -o managed "d:/tmp/mail" "/home/of/mail"
    
    substituting the windows-path directory you wish to use for mail for the "d:/tmp/mail" above, and the mount point you wish to put it on instead of "/home/of/mail".
  • Once you have IMAP-to-Maildir synchronization going to your local PC, then you're good to go with offline IMAP stuff and Mutt. Follow the usual directions for configuring Mutt to use the Maildir you've set up, paying particular attention to choice of outbound mailer (probably ssmtp).
Obviously, though I'm a big fan of Mutt, that seemed like a lot of work. Lucky me, I chanced across a script that, with minor modifications, gave me the primary thing I loved about using Mutt: being able to use vim as my text editor. I'm just much faster using that than any other editor, and it's ubiquitous on UNIX systems, either in a more-primitive incarnation of "vi", or in some version.

So I installed Python and the Win32 extensions for Python, then linked this script on my quickbar in Windows, conveniently right next to Outlook:

#!/bin/env python
'''
outlook.pyw (OutLook editor launcher) -- allows one to edit an open e-mail
      mesg from Outlook using Emacs or *Vi* rather than "Notepad--".  :-)
      NOTE:  requires Python 1.6 and newer (use of string methods)

created by John Klassa (klassa at employees.org) on 2001 May 29
updated by Wesley Chun (cyberweb at rocketmail.com) on 2002 Feb 28

$Id: outlook.pyw,v 0.2 2002/08/28 18:04:06 wesc Exp wesc $
'''

from os import spawnv, P_WAIT, unlink
from tempfile import mktemp
from Tkinter import Tk, Button, Frame, Label
from Tkconstants import *
from win32com.client import Dispatch

def launch():
    '''launch() spawns your favorite editor to edit the Outlook compose 
    window (either new or reply), then returns that data to Outlook...
    change the 'ed' variable to switch editors.'''

    # Get a handle to Outlook.
    o = Dispatch("Outlook.Application")

    # Work our way down to the reply (a "MailItem").
    insp = o.ActiveInspector()
    if insp == None: return
    item = insp.CurrentItem
    if item == None: return

    # Grab the message body in the reply.
    body = item.Body

    # Write the body... need to "encode" the string because Outlook uses
    # Unicode with bunch of unprintables (ASCII chars > 128).  Also, since
    # we are going from DOS2UNIX2DOS, we have the \r\n vs \n issue, re-
    # sulting in those fabulous ^M characters.  A persistent, bound-to-a-
    # key Emacs macro takes care of that nicely, but the solution imple-
    # mented here is to just wipe the '\r's now, then add them back when
    # we reread this file back before returning the body to Outlook.
    tmp = mktemp()                  # generate a unique tmp filename
    fh = open(tmp, "w")
    fh.write(body.encode('ascii', 'ignore').replace('\r\n', '\n'))
    fh.close()

    # Launch editor to edit the file (should make this configurable).
    #ed = r"d:\emacs-20.7\bin\emacs"            # emacs editor binary
    ed = r"c:\vim\vim62\gvim.exe"   # *vi*  editor binary
    spawnv(P_WAIT, ed, [ed, tmp])

    # Read edited file back into memory, restore '\r's, and kill tmp file.
    fh = open(tmp)
    body = fh.read().replace('\n', '\r\n')
    fh.close()
    unlink(tmp)

    # Store it as the body of the reply.  Note that we are merely
    # sending this data back to Outlook -- it does not prevent MS from
    # mucking with your message.  For example, it may add your signature
    # again, or it may remove newlines.  MS software... what can you do?
    item.Body = body

# Create the Tk(inter) GUI app with the appropriate label and buttons.
if __name__=='__main__':
    tk = Tk()
    f = Frame(tk, relief=RIDGE, borderwidth=2).pack()
    Label(f, text="Outlook Edit Launcher v0.2").pack()
    Button(f, text="Edit", fg='blue', command=launch).pack(fill=BOTH)
    Button(f, text="Quit", fg='red', command=tk.quit).pack(fill=BOTH)
    tk.mainloop()

I now click Outlook, then click my outlook.py script. I minimize the annoying black cmd window that comes up (anybody know how to get rid of this?), and I now have a little Python/TK window with a convenient "edit" button on it. When I compose a message in LookOut, I click this "edit" button, and up pops gvim 6.2, ready for me to type the message. When I'm done typing it, I just write-quit out of gvim, and the text pops up in my Outlook compose window.

Convenient! Well, for a UNIX-geek at least.

Anyway, I'm still torn. Do I really need to use Outlook here? Realistically, I have maybe one meeting a week that I need to keep track of, and that's easily done in my Palm. Maybe I should just use Mutt in Cygwin on a managed mount? Who knows, but both are valid choices. And in a world where MS wants you to only use MS products, and those products are funkily generic and slow, it's nice to have choices.

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Sammy G's picture

That's so 1990s

Matt, c'mon man, who isn't using Mutt in Cygwin on a manager mount these days? Get with the times dude.

Here's a question: say a small firm is setting up an office for 5 employees. The set up is going to be a server-client network (no shared apps). Do you recommend going with a MS Windows or Mac OS system? Are there choices in buying out-of-the-box or configurable servers and workstations that can house popular software, don't cost an arm and a leg and give choice?

Wondering if you can go out and buy the computing pieces and then run a freeware OS and pick and choose your components...and if it makes compatibility and cost sense...

BTW -- I'm not trying to diminish the genius of your original post, it's just that I don't understand it. :)

matthew's picture

Well, you brought up a very g

Well, you brought up a very general topic. So I'm going to give generic advice for setting up a small office network on the cheap.

The first thing to realize is that "freeware", or "open source" is only free if your time is worth nothing. If you know nothing about what you're doing, you'll be paying a consultant to do it right regardless of what platform you choose. You can do it "on the cheap" on your own, but you'll be learning a lot as you do so :)

There are several basic components to any office setup, some of which may be optional depending on your situation and type of business:

    Infrastructure:
  • Electronic Mail System
  • Shared calendaring system
  • Telephone (PBX) System
  • Fax system
  • File-Sharing
  • Web presence (lots to this, depending on what you wish to do)
  • Switch, router, and firewall
  • Documentation management
  • Customer Relationship Management
  • Web browser
  • Email reader
  • Office suite
  • Domain-specific applications (Photoshop for the artist, Lightwave for the modeler, etc.)
  • Accounting package(s)
  • Project management

With all of these, you can pick-and-choose where you want technology to assist you, and where you wish to do things by hand. You can also choose to outsource much of it, pick a closed-source application, or pick an open-source app that you can modify to suit your needs.

My default rule in new buildouts is to use open-source ("free" or "libre") software wherever possible. I can make that default choice without additional justification if it's capable of meeting the needs of the client. If I must choose a proprietary application (such as Microsoft Exchange), I then need to give justifications for that choice.

For desktops, if it is feasible, I would choose GNU/Linux. Which distribution is probably irrelevant, but for ease of updating, and due to some idealistic concerns regarding free software, I would probably pick Debian.

If I had to choose between MacOSX and Windows, I would pick MacOSX in a heartbeat. At its core, it is a UNIX-based operating system. It is also less popular than MS Windows, and in this age of monoculture computer virusses, that alone is an excellent justification. It has all the domain-specific apps people need in a creative workshop, runs on standardized hardware that, while expensive, has a much lower failure rate than commodity PCs, and has a definite sex appeal :)

On the server side, I'd buy one really fast, capable dual-processor PC with 2 GB+ RAM, a 64-bit processor (AMD or Intel), running GNU/Linux. Possibly, if you want to stay an all-Mac shop, a Mac rackable G5 server would be a good choice for this, too. Run all the critical services on this one box, and maybe set up a second one with an identical configuration so you have a backup in case the primary fails.

I could write an essay about this, so I'll stop now.

--
Matthew P. Barnson

--
Matthew P. Barnson

weed's picture

The MS Way

Matt,

Try this:

  1. Copy the following into a file and name it 'launchvim.vbs'
    Option Explicit
    
    Private Sub launch()
    
          Const TemporaryFolder = 2
    
          Dim ws, ol, insp, item, body, fso, tempfile, tfolder, tname, tfile
    
          Set ol = CreateObject("Outlook.Application")
    
          Set insp = ol.ActiveInspector
          If insp Is Nothing then
                Exit Sub
          End if
          Set item = insp.CurrentItem
          If item Is Nothing then
                Exit Sub
          End if
    
          body = CStr(item.Body)
    
          Set fso = CreateObject("Scripting.FileSystemObject")
          Set tfolder = fso.GetSpecialFolder(TemporaryFolder)
          tname = fso.GetTempName
          Set tfile = tfolder.CreateTextFile(tname)
          tfile.Write( Replace( body, Chr(13) & Chr(10), Chr(10) ) )
          tfile.Close()
    
          Set ws = WScript.CreateObject("WScript.Shell")
          Wsh.Echo( "c:\vim\vim62\gvim.exe " & tfolder.Path & "\" & tname )
          ws.Run "c:\vim\vim62\gvim.exe " & tfolder.Path & "\" & tname ,4, true
    
          Set tfile = fso.OpenTextFile(tfolder.Path & "\" & tname, 1 )
          item.body = Replace( tfile.ReadAll, Chr(10), Chr(13) & Chr(10) )
          tfile.close()
    
          fso.DeleteFile( tfolder.Path & "\" & tname )
    
    End Sub
    
    Call launch()
    
    
  2. In Outlook, Go To Tools->Macros->VB Editor (Make sure your Security settings for Outlook are set to Medium)
  3. Add a new module, and paste this into it
    Sub LaunchVIM()
    
        Dim windir As String
    
        windir = Environ("WinDir")
    
        Shell (windir & "\system32\cscript.exe " & windir & "\system32\launchvim.vbs")
    
    End Sub
    
    
  4. Open a new Outlook mail message
  5. Click View->Toolbars->Customize
  6. Under the Commands tab, Select Macros on the left, and drag the macro you just created to the Outlook toolbar in your newly opened mail dialog.
Voila! Now you can launch vim from the Outlook toolbar!

EDIT by matthew: cleaned up formatting for slightly easier readability.

My $.02
Weed

matthew's picture

SWEET!

Pretty sweet, dude. I now have a "Project1.LaunchVIM" button on my toolbar. Unfortunately, setting security to Medium violates our corporate security policy. So I reset it back to High after installing the button, and the button continues to work fine.

So, for future security-conscious readers, set to Medium to install the script, then back to High and your script will continue to run without problems. How long did it take you to whip that out, Weed? I know next to nothing about Visual Basic, but it is visually much cleaner (and easier to install) than a separate Python window with an "EDIT" button :)

--
Matthew P. Barnson

--
Matthew P. Barnson

weed's picture

Uh-oh

Matt

The security feature of the macros takes place after the next restart, so more than likely the next time you open Outlook your button won't work.

I'll look into signing the code so it works with High. You may have to install my company's cert authority tho, 'cause I'm not paying Veri$ign to sign it.

As for VBScript, it's not hard. http://msdn.microsoft.com/ has a bunch of information on it, but, as with all Microsoft, you have to learn how to search for it.

Look here:
http://www.microsoft.com/technet/prodtechnol/office/office2000/maintain/...

My $.02
Weed

matthew's picture

Roger that

Yeah, just fired up Outlook again, and the button does nothing. Durn.

For now, I'm continuing to use my offlineimap/Mutt/Cygwin solution. It works very well to keep the folders synchronized, but stuff like seeing other users' folders just doesn't work at all, so I have to keep Outlook around.

--
Matthew P. Barnson

--
Matthew P. Barnson

Change the .py to .pyw

Getting rid of the python console is easy - change the file extension. The app will work and the console will not be spawned.

matthew's picture

.py to .pyw

Changing the file extension to .pyw worked like a champ for getting rid of the console window; thanks for the tip!

--
Matthew P. Barnson

--
Matthew P. Barnson

Restoring the text format

Hi Weed, this script works well for me. It is very useful and productive for Vim fans like me! I am looking for one more feature. Right now, when I return back from my Vim session the file type is set to 'rich text' irrespective of the state before editing in vim. Is it possible to restore the text format. If that is not possible, how to set it to 'plain text' which makes more sense when we edit using vim (the nice indentations will show up the same way in outlook)

Thanks
--Mahesh N

How to sign it

See this page
for how to sign the thing. Working for me now.

--
Paul Wright

EDIT by matthew: linked.

matthew's picture

Mail format

Unfortunately, this is a change you have to make in Outlook, not in your configuration for using VIM.

In Outlook, go to the Tools menu and select Options. Click the "Mail Format" tab, and change the "Compose in this message format" from "Rich Text" to "Plain Text". The problem is then solved, and you have your nice indentation and mail config.

I'm in this same boat again today, since I'm working a new job where they use Outlook exclusively. And, in this case, Outlook is extremely tied-in to their basic management systems, so using Mutt to the exclusion out Outlook is no longer an option (sigh)... So I came back to this page this morning to remember how I did it!

Anyway, changing those options will do the trick. The one annoyance left is that with the latest patches to Outlook, every time I launch this I get a prompt saying "A program is trying to access your Address Book", and I have to click "Yes" to allow it to run. It's only one extra click, but I do this in part for convenience. I've been digging around trying to figure out how to turn this off for a signed, truested vbscript, but no luck.

However, the tips above on signing your own code work great to make it work appropriately, with the exception of that annoying pop-up every time I compose a mail message.

The price I pay for being a UNIX geek, I guess... maybe I'll go back to using Mutt on Cygwin for email, and just use LookOut for calendars, contacts, etc.

--
Matthew P. Barnson

--
Matthew P. Barnson

what if we don't have gvim installed?

I use non-gui version of vim under Windows XP + cygwin, and I am not willing to install another windows version gvim at the moment. Is it possible to tailor these scripts so that it works under such environment?

I am always wanting tweaks such that whenever windows calls for a text editor, it invokes rxvt + vim, is this possible?

Thanks,

Jindan

matthew's picture

Yes, replacement

Jindan,

Yes, replacement is trivially easy in each of these scripts in order to use the cygwin version of vim instead of the native Win32 gvim. Simply everywhere it currently calls c:\some_path\bin\vim, replace it with c:\your_cygwin_path\bin\rxvt -e vim.

For instance, in my case, my Cygwin root is in d:\cygwin. I would replace this line:

ed = r"c:\vim\vim62\gvim.exe"   # *vi*  editor binary

with this one:

ed = r"d:\cygwin\bin\rxvt.exe -e vim"   # *vi*  editor binary

Just tested it, done and done. So the Python version is figured out; you'd need to adjust it similarly if you were to use Weed's Visual Basic version on the parent page. I'm not using either one anymore, at the moment, because I'm so sick of Outlook. I went back to using OfflineIMAP + Mutt on a Cygwin managed mount because it's so much faster, and I can run it remotely without having to use some sort of remote desktop. If I get an appointment in my inbox that requires their synchronization tool, I note the time of the appointment in my Palm Pilot, and next time I'm in the office I might fire up Outlook to confirm the appointment (or just show up; people around here rarely seem to care if you actually RSVP for the meeting or not).

Curiously, my new company's Exchange server doesn't create nearly the havoc with offlineimap that the old one did. I wonder if they improved their IMAP support in the latest version?

--
Matthew P. Barnson

--
Matthew P. Barnson

That is so cool!

This is what I did, first I created vim.bat in c:\program files\cygwin\bin with this line:

start rxvt -sr -sl 2500 -geometry 90x30 -fg grey70 -bg midnightblue -fn "Lucida ConsoleP-16" -e vim %1

Then I changed the View Source program from Notepad to vim.bat, worked out like a charm! Since many of the IE temp file doesn't have an extension file name, I need to manually type

set syntax=html

to enable syntax highlighting each time. Trying to figure out a workaround now.

Weed's code doesn't work out (yet), when I press the macro button, the screen flashed as if something happening, but then nothing. Is there a log that I can check in VB editor or Outlook so that I can tell what happened?

matthew's picture

syntax highlighting

Try adding these lines to your $HOME/.vimrc file (this varies according to installation, the easiest way is to just do "vi ~/.vimrc" from a cygwin shell):

"turn on syntax highlighting
:syntax on

Now it's possible that vim may not recognize your terminal type. In order to work around this (like if syntax highlighting won't turn on from this one addition to your .vimrc), then try adding these to your ~/.vimrc:

"fix inability to read term type
:set term=xterm-color

--
Matthew P. Barnson

--
Matthew P. Barnson

I think the problem is with ...

That the IE temporary files are sometimes without an explicit extension name, i.e. .html, .htm, etc., thus vim can't find a proper syntax highlighting scheme, even though I have "syntax on" set in my .vimrc file.

Okay, the prolem is solved by ...

modifying my vim.bat as followed:

start rxvt -sr -sl 2500 -geometry 90x30 -fg grey70 -bg midnightblue -fn "Lucida ConsoleP-16" -e vim -c "set syntax=html" %1

Thanks, Matt!

matthew's picture

syntax=mail

You'll get even better results with syntax highlighting if you do a:

vim -c "set syntax=mail" %1

Vim's very smart about email syntax, understanding quoting and such. Since I prefer a dark background with light text, I'd add this to my .vimrc as well:

:colorscheme murphy

Other light-on-dark colorschemes that work well are "torte", "evening", and "ron".

Good luck!

:wq!

--
Matthew P. Barnson

--
Matthew P. Barnson

Alternatively

Since Windows runs programs based on extension and not MIME-type, setting the first line in the script to:

#!c:\python24\pythonw.exe 

will do the same thing.

Python for Windows associates *.py with python.exe and *.pyw with pythonw.exe.

The Python code strips accented letters from Outlook

fh.write(body.encode('ascii', 'ignore').replace('\r\n', '\n'))
likely is the reason that accented letters like é in Gérard end up being dropped :-(
This severely limits an otherwise very good call to VIM for Outlook.

Any fix?

matthew's picture

encoding...

I'd think replacing "ascii" with a Unicode encoding such as "Latin-1" might do the trick, or, more likely, eliminate the body.encode call entirely and try just doing an fh.write. Unfortunately, I've stopped using this program for "real" work, so I don't have a way to test it.

You'll also have to make sure your Vim is set up to handle Unicode, which is an area where I have to claim utter ignorance :)

Additionally, I don't know that the whole stripping \r\n thing is even necessary in the Windows version of Vim today. The one I'm running now handles DOS-formatted files without a hiccup.

--
Matthew P. Barnson

--
Matthew P. Barnson

Weed's code

It doesn't work for me (yet). I tried debugging the script and found that the GetInspector methor returns "Nothing" - I have Microsoft Outlook 2003. I went to outlookcode.com and obtained a few test scripts - all of them exit with the same result - GetInspector returns nothing. Does anyone have any clues to offer?

Thanks in advance,
Girish

No replies yet?

:(

Problem with VBS

Hi,

I successfully created the launchvim.vbs script and the acompanying VB Makro. But vim doesn't start when clicking on the macro-button in the toolbar. Does anyone have a clue?

I'm using Outlook 2003 and VIM 7.0

weed's picture

Here's the new version

All,

I changed the code up a bit. Here are the new steps.

1) In Outlook, click Tools->Macro->Visual Basic Editor
2) Under Tools->References, make sure Microsoft Scripting Runtime is selected. Close out of the dialog
3) Either create a new module or use and existing one
4) Paste the following code into the module:

Option Explicit

Private Type STARTUPINFO
   cb As Long
   lpReserved As String
   lpDesktop As String
   lpTitle As String
   dwX As Long
   dwY As Long
   dwXSize As Long
   dwYSize As Long
   dwXCountChars As Long
   dwYCountChars As Long
   dwFillAttribute As Long
   dwFlags As Long
   wShowWindow As Integer
   cbReserved2 As Integer
   lpReserved2 As Long
   hStdInput As Long
   hStdOutput As Long
   hStdError As Long
End Type

Private Type PROCESS_INFORMATION
   hProcess As Long
   hThread As Long
   dwProcessID As Long
   dwThreadID As Long
End Type

Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal _
   hHandle As Long, ByVal dwMilliseconds As Long) As Long

Private Declare Function CreateProcessA Lib "kernel32" (ByVal _
   lpApplicationName As Long, ByVal lpCommandLine As String, ByVal _
   lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, _
   ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, _
   ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As Long, _
   lpStartupInfo As STARTUPINFO, lpProcessInformation As _
   PROCESS_INFORMATION) As Long

Private Declare Function CloseHandle Lib "kernel32" (ByVal _
   hObject As Long) As Long

Private Const NORMAL_PRIORITY_CLASS = &H20&
Private Const INFINITE = -1&

Sub LaunchVIM()

    'Dim windir As String

    'windir = Environ("WinDir")

    'Shell (windir & "\system32\cscript.exe " & windir & "\system32\launchvim.vbs")
    
    Const TemporaryFolder = 2
    Const VIMLocation = "C:\Program Files\Vim\vim70\gvim.exe"

    Dim ol, insp, item, body, fso, tempfile, tfolder, tname, tfile, appRef, x

    Set ol = Application

    Set insp = ol.ActiveInspector
    If insp Is Nothing Then
        Exit Sub
    End If
    Set item = insp.CurrentItem
    If item Is Nothing Then
        Exit Sub
    End If

    body = CStr(item.body)

    Set fso = CreateObject("Scripting.FileSystemObject")
    Set tfolder = fso.GetSpecialFolder(TemporaryFolder)
    tname = fso.GetTempName
    Set tfile = tfolder.CreateTextFile(tname)
    tfile.Write (Replace(body, Chr(13) & Chr(10), Chr(10)))
    tfile.Close

    ExecCmd VIMLocation & " " & Chr(34) & tfolder.Path & "\" & tname & Chr(34)

    Set tfile = fso.OpenTextFile(tfolder.Path & "\" & tname, 1)
    item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10))
    tfile.Close

    fso.DeleteFile (tfolder.Path & "\" & tname)

End Sub

Public Sub ExecCmd(cmdline$)
    
    Dim proc As PROCESS_INFORMATION
    Dim start As STARTUPINFO
    Dim ReturnValue As Integer

    ' Initialize the STARTUPINFO structure:
    start.cb = Len(start)

    ' Start the shelled application:
    ReturnValue = CreateProcessA(0&, cmdline$, 0&, 0&, 1&, _
      NORMAL_PRIORITY_CLASS, 0&, 0&, start, proc)

    ' Wait for the shelled application to finish:
    Do
        ReturnValue = WaitForSingleObject(proc.hProcess, 0)
        DoEvents
    Loop Until ReturnValue <> 258

    ReturnValue = CloseHandle(proc.hProcess)
    
End Sub

Now follow the above intructions on creating a toolbar button that launches the Macro "LaunchVIM"

This method keeps everything in VBA and strips out the VBScript external application as well as the WSH junk.

This post used massive amounts of cut-and-paste programming from examples provided at the MS MSDN site. All the answers are there, however finding them is the trick. ;)

My $.02
Weed

My $.02
Weed

matthew's picture

Colorized!

And, of course, the preceding code... colorized!

Yeah, I'm useless. But I like coloring books.

Option Explicit

Private Type STARTUPINFO
   cb As Long
   lpReserved As String
   lpDesktop As String
   lpTitle As String
   dwX As Long
   dwY As Long
   dwXSize As Long
   dwYSize As Long
   dwXCountChars As Long
   dwYCountChars As Long
   dwFillAttribute As Long
   dwFlags As Long
   wShowWindow As Integer
   cbReserved2 As Integer
   lpReserved2 As Long
   hStdInput As Long
   hStdOutput As Long
   hStdError As Long
End Type

Private Type PROCESS_INFORMATION
   hProcess As Long
   hThread As Long
   dwProcessID As Long
   dwThreadID As Long
End Type

Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal _
   hHandle As Long, ByVal dwMilliseconds As Long) As Long

Private Declare Function CreateProcessA Lib "kernel32" (ByVal _
   lpApplicationName As Long, ByVal lpCommandLine As String, ByVal _
   lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, _
   ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, _
   ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As Long, _
   lpStartupInfo As STARTUPINFO, lpProcessInformation As _
   PROCESS_INFORMATION) As Long

Private Declare Function CloseHandle Lib "kernel32" (ByVal _
   hObject As Long) As Long

Private Const NORMAL_PRIORITY_CLASS = &H20&
Private Const INFINITE = -1&

Sub LaunchVIM()

    'Dim windir As String

    'windir = Environ("WinDir")

    'Shell (windir & "\system32\cscript.exe " & windir & "\system32\launchvim.vbs")

    Const TemporaryFolder = 2
    Const VIMLocation = "C:\Program Files\Vim\vim70\gvim.exe"

    Dim ol, insp, item, body, fso, tempfile, tfolder, tname, tfile, appRef, x

    Set ol = Application

    Set insp = ol.ActiveInspector
    If insp Is Nothing Then
        Exit Sub
    End If
    Set item = insp.CurrentItem
    If item Is Nothing Then
        Exit Sub
    End If

    body = CStr(item.body)

    Set fso = CreateObject("Scripting.FileSystemObject")
    Set tfolder = fso.GetSpecialFolder(TemporaryFolder)
    tname = fso.GetTempName
    Set tfile = tfolder.CreateTextFile(tname)
    tfile.Write (Replace(body, Chr(13) & Chr(10), Chr(10)))
    tfile.Close

    ExecCmd VIMLocation & " " & Chr(34) & tfolder.Path & "\" & tname & Chr(34)

    Set tfile = fso.OpenTextFile(tfolder.Path & "\" & tname, 1)
    item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10))
    tfile.Close

    fso.DeleteFile (tfolder.Path & "\" & tname)

End Sub

Public Sub ExecCmd(cmdline$)

    Dim proc As PROCESS_INFORMATION
    Dim start As STARTUPINFO
    Dim ReturnValue As Integer

    ' Initialize the STARTUPINFO structure:
    start.cb = Len(start)

    ' Start the shelled application:
    ReturnValue = CreateProcessA(0&, cmdline$, 0&, 0&, 1&, _
      NORMAL_PRIORITY_CLASS, 0&, 0&, start, proc)

    ' Wait for the shelled application to finish:
    Do
        ReturnValue = WaitForSingleObject(proc.hProcess, 0)
        DoEvents
    Loop Until ReturnValue  258

    ReturnValue = CloseHandle(proc.hProcess)

End Sub


--
Matthew P. Barnson

--
Matthew P. Barnson

weed's picture

Do Tell

How did ye colorize it?

Weed

My $.02
Weed

matthew's picture

Copy/paste

I use... what else? Vim :) In this case, specifically, gvim, but you can do it from any version.

Copy and paste into vim.

:cal SetSyn("vb")
:syntax on
:set background=light
:runtime! syntax/2html.vim
ggVG (to select all in this top frame)
"+y (to copy to clipboard)

Then paste using whatever method you use to paste. gvim makes this easier than console-based vim, as you can use drop-down menus instead of console commands. I just trim the header & footer information, and then post!

I think it works fine with filtered HTML (the Drupal default), but it may not. I use full html mode to post.

--
Matthew P. Barnson

--
Matthew P. Barnson

weed's picture

VIM and outlook

You don't use VIM w/Outlook anymore though, do you?

I don't use VIM at all (except for rare cases), but I can't have my code not working. It's a problem I have...

My $.02
Weed

My $.02
Weed

matthew's picture

Enlightened employer

Until March 1, 2006, I used Vim/Outlook all the time with my employer. My company was acquired by a new company which is far more enlightened about their IT policies... they use Linux extensively, and almost exclusively, for server infrastructure. I normally use Thunderbird with some plugins or their web-based collaboration suite, either of which support Vim just fine.

Firefox + mozex for Vim in a textarea via the web interface.
For Vim in Thunderbird, I use the External Editor extension: http://www.appliedmiscellany.com/blog/archives/22

--
Matthew P. Barnson

--
Matthew P. Barnson

Vim with Thunderbird/Firefox

For using Vim with Thunderbird/Firefox, I highly recommend the ViewSourceWith extension (http://dafizilla.sourceforge.net/viewsourcewith/). Works even better than External Editor.

matthew's picture

Thanks!

Thanks for that! It's worthwhile to note how old the original blog entry is though.... ViewSourceWith wasn't written at the time I wrote the original. I always expect humanity to better a good idea.

--
Matthew P. Barnson

--
Matthew P. Barnson

problems when gvim installed in "Program Files" dir

Matt,

I'm trying to use your script with gvim, which I have installed in the "Program Files" directory. Here's the line I changed in the script:

ed = r"c:\Program Files\Vim\vim70\gvim.exe" # *vi* editor binary

Only problem is that when I try to write-quit out of gvim, I get the following error:

"Files\Vim\vim70\gvim.exe" E212: Can't open file for writing

I think it's having issues with the space between "Program" and "Files" in the path to the .exe.

Any ideas?

Ben

matthew's picture

Progra~1

Have you tried using "Progra~1" instead? I think that's the DOS name.

--
Matthew P. Barnson

--
Matthew P. Barnson

weed's picture

dir /x

If you open a command prompt and go to the C: drive, then type dir /x, it'll show you the normal name and the 8.3 dos name. But Matt's right, 99.9999999% of the time, it'll be Progra~1.

My $.02
Weed

My $.02
Weed

Progra~1

Great! That worked like a charm. Thanks for the help guys!

Ben

Issues with customizing toolbar

Hi,

I tried Weed's second post for how to set this up but when I try to customize the toolbar in the compose email window there are no macros available in the dialog window (however, the macros do appear when I customize the main mail window). I'm using Outlook 2003 on Windows XP. Please let me know if you have any ideas.

Cheers.

matthew's picture

At least for me...

At least for me, time moves on and so did I. My new company is very tolerant of open-source software, so I'm back to using Mutt on Linux for 99% of my mail needs. Sorry I can't help; maybe Weed can chime in?

--
Matthew P. Barnson

--
Matthew P. Barnson

weed's picture

Don't Compose Using Word

I bet you're using Word to compose email messages. The script won't work if you're using Word as your email editor, although it might be tweaked if you want to play with it. I don't have time now.

To see if Outlook is using Word as your email editor, from the mail Outlook window, click Tools->Options, and look on the Mail Format tab.

My $.02
Weed

My $.02
Weed

Newlines Messing Up

FWIW, I found that using the second version of the VB macro code above was screwing up all of the newlines in my gVim-written text. I was able to fix the problem by changing these lines:

'item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10))
item.body = tfile.ReadAll
...
'tfile.Write (Replace(body, Chr(13) & Chr(10), Chr(10)))
tfile.Write (body)

My problem was probably due to some combination of my Outlook composition settings (Plain Text Only) and the way gVim handles newlines.

weed's picture

I Forget

I forget why I put that in there in the first place. Maybe a previous version of Vim on Windows had Unix-style newlines, and I needed to convert them to Windows-style newlines.

Your replacement is much cleaner in that there's no text "search and replace" going on to slow things down.

My $.02
Weed

My $.02
Weed

I got it to work with vim,

I got it to work with vim, but any idea how to get it to work in emacs?

I changed the vim references & paths to the emacs path (runemacs). When I hit the button, emacs launces & edits a file in the TEMP directory with a name of the appropriate form, but it isn't the same file that Outlook is using.

In vim, my signature is included, and when I save & quit, the edited text shows up in Outlook.

In emacs, my signature isn't there and my edits are not in Outlook when I quit.

matthew's picture

emacs vs. vi

emacs sucks. vi rules. I mean, it's a great operating system which lacks only a decent text editor...

--
Matthew P. Barnson

--
Matthew P. Barnson

weed's picture

Hmm

So if you click the button to edit in Emacs, anything already in the Outlook compose window doesn't show up in the Emacs editor?

Open the temp file Outlook creates with another text editor (vi, notepad, etc) and see if the text is in there. If so, maybe we need to call emacs with the temp file location differently. I can't imagine it's NOT there as it works for vi.

Also, what version of emacs, Outlook, and OS are you running?

My $.02
Weed

My $.02
Weed

Yes, you are correct: the

Yes, you are correct: the vim version works, but it seems like there's no interchange of data in *either* direction with emacs: Emacs opens ~a~ temporary file, but doesn't seem to open the
~correct~ temp file, but I don't have the VBA background to understand how the data is exchaged.

I'm running Emacs 22.1.1 and Outlook 2003 under XP Pro.

If I open a new Outlook message, type "weed" in the box, and click LaunchVIM, then vim opens C:\TEMP\radA92AD.tmp which contains "weed." If I immediately click Project1.LaunchEmacs, then emacs edits a blank file C:\TEMP\rad54E92.tmp

But what really causes a problem, is that
Open new message in Outlook
Click Project1.LaunchVIM
In vim, type iweed Esc :wq!
Results in a message containing the word "weed"

But
Open new message in Outlook
Click Project1.LaunchEmacs
In emacs, type weed ^x^s ^x^c
Results in a still-blank Outlook message

Secondly, there's a bit of a bug in the VB: In either editor, I get a runtime error "attempt to navigate past end of file." The offending line is:
item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10))

This happens when starting VIM on a blank (no signature*) email, but, tellingly, not when launching Emacs.

Lastly, since we're doing this largely to work in keyboard-based editors, can we assign a hotkey to the macro, or is Alt-F8, Enter the best way to invoke these? Can Outlook be instructed to run this on every new message? If one did auto-invoke, would it break stuff like meeting replies? (sorry; I'm a little new to Outlook)

*I'm using Autohotkey hotstrings for my various signatures:
1. I find it more flexible to insert an internal, external, or no signature explicitly rather than often having to select and delete a sig.
2. Some company systems have me sending mail from a Web form, where OL signatures don't exist.

RE: Editor War

I'm pretty ecumenical...I almost have to be given that vi was written by a Michigan alumnus :)

In college (outside of Michigan), I was not properly instructed in the power features (repeating commands, etc.) of vi to justify the initial investment in learning it. A fellow student misled me into pico for a while, then, seeking more power, I got into emacs. I don't think vim, with its language modes, was very popular then yet, either, so I tried to learn emacs. Over the years, I've put time into emacs in fits & starts.

I'm technically a salesman not a programmer, so I can't really master multiple editors.

Somebody put together a really nice Web page showing the powerful macros that you can do with vi that almost made me want to switch, but, again, I can only invest in learning one editor really well. And that's what's great about this page: it's efficient to use the same set of editing commands in as many contexts as possible.

Along those lines, it's probably good to implement some basic vi commands as an autohotkey script.

I actually use sort of a hybrid vi/emacs key layout, which might be a bad idea: I use the middle button above the trackpad on as a modifier to implement the following:
mbutton & h backspace
mbutton & j left
mbutton & k up
mbutton & l down
mbutton & ; right
mbutton & ' delete
mbutton & u ^left (usually back one word)
mbutton & p ^right (usu forward word)
mbutton & i/o page up/page down (up / down screen)
mbutton & n backspace word
mbutton & , ^HOME (or BACK in Firefox...)
mbutton & . ^END (or FORWARD in Firefox...maybe should keep as ctrl-end in FF to scroll to the bottom of long Web pages)

So, for what it's worth, I get vi's home-row navigation in a non-modal context.

I'm waiting on a keyboard for the office...I might use the left Windows key if I don't have a middle button.

RE: Editor War

Oh, and in my scheme, the letter m is HOME and / is END.

I looked at Xah Lee's "ergonomic keyboard layout for emacs," while I was working through this.

The IBM middle button is kind of nice, since it falls directly under my left thumb and I always used my right hand for the spacebar anyway.

What kind of sucks (at least in autohotkey) is that I don't think you can use any other modifier with a mouse button a modifier. So shift and ctrl don't work in this scheme. I think I used Capslock-[ and Capslock-]to go into "shift mode," but that was too complicated even for me.

weed's picture

Try this

Every time you click the button (be it the Emacs one or the Vi one), it creates a new temp file. So the fact that the tmp files have different names isn't an issue. W

What I would want to try is to type some text into the compose window, and hit your Emacs button. You'll see the tmp file it wants to open. While keeping the Emacs editor open, try and open that same tmp file in vi or notepad or whatever. I want to see if the text you typed into the Outlook compose window is getting to the temp file, and it's just emacs isn't opening it correctly. Or, if for some reason when Emacs opens the temp file it clobbers the contents (or does some sort of silly renaming thing like notepad does, putting a .txt on the end of everything).

With respect to the bug, try replacing this:
item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10))

With this:
Dim ftxt
ftxt = tfile.ReadAll
item.body = Replace(ftxt, Chr(10), Chr(13) & Chr(10))

It may still error, but it'll give me a better idea of which statement is causing the error.

See this MS KB article about assigning hotkeys to macros. Note it's for Outlook 2002, but it should work in your case: http://support.microsoft.com/kb/292798/en-us

As for auto-invoke, would you want this macro to run on every message which comes in, or would you want this macro to open your compose window for you?

My $.02
Weed

My $.02
Weed

matthew's picture

emacs & vi

...almost made me want to switch, but, again, I can only invest in learning one editor really well.

Truth be told, I actually use both editors frequently. emacs in psgml mode is, for me, much more intuitive when editing SGML, XML, or sometimes even HTML documents. vi is more intuitive when I'm programming in python, bash, or perl. On my workstation I run both frequently.

I just tend to land in the vi camp most often because I administer a farm of thousands of servers. vi is the lowest-common-denominator editor everywhere. I miss vim's extension, color, and syntax support when I'm on a remote machine, though, and often as not write the code chunk on my local workstation and paste it into the remote window.

You've lost me on the problems integrating emacs into Outlook, though... I stopped using outlook the day after UltraMegaCorp announced that the new mail standard allowed "open source clients" in addition to Outlook. I sync the calendar to my Windows Mobile Device (pretty much the only place I look for calendar and task info), and have used Mutt and Thunderbird for handling mail. I used Mutt for many years until last week, and decided to try Thunderbird. I've been impressed with the number of keyboard shortcuts so far, which was my big complaint with most GUI mail programs.

Next project: integrating vi into Thunderbird :) Thunderbird's spell-checker stinks, it won't format plain text correctly, it won't let me modify text I'm replying to without munging the formatting... yuck! But it's a decent mail reader, and with a dovecot backend rather than Maildir it's much faster searching email than Mutt was. Of course, that's a Dovecot feature more than a Thunderbird feature.

I'll have to blog my setup one day. I'm totally using the corporate mail system, yet I'm not allowing myself to be subject to their limiting "features" (Teeny, tiny quotas! Augh!) by using my own mail server and keeping regular backups. It's pretty trivial on a Linux box, and only slightly more difficult on a Windows machine (via Cygwin).

--
Matthew P. Barnson

--
Matthew P. Barnson

New outlook message Type

New outlook message
Type "Weed" in the message box
Click Project1.LaunchVIM
vim shows C:\temp\rad38D7E.tmp contains "Weed"
launch command line
type runemacs C:\temp\rad38D7E.tmp
result: emacs opens the file and it contains "Weed"
in emacs: type ^e "enjoys adult panda movies" ^x^s^x^c
VIM shows Warning that the file has changed; hit "Load file", hit Esc :q!
Outlook now shows "Weed enjoys adult panda movies"

So if I manually give runemacs the right filename, it works. The question is why it is getting a different temp file.

----------
To the VB error, now the breakpoint is
ftxt = tfile.ReadAll

I think the answer is in:
http://www.microsoft.com/technet/scriptcenter/guide/sas_scr_eqco.mspx

But when I took out the Dim and went back to your original line but wrapped in an if:
If tifle.Size > 0 Then
item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10))
End If

Now I get an error '438': "Object doesn't support this property or method" when I close VIM. The breakpoint is
If tfile.Size > 0 Then