// +build windows package main import ( "fmt" "time" "syscall" "unsafe" ole "github.com/go-ole/go-ole" "github.com/go-ole/go-ole/oleutil" ) var ( CLSID_IConverterSession = ole.NewGUID("{4e3a7680-b77a-11d0-9da5-00c04fd65685}") IID_IConverterSession = ole.NewGUID("{4b401570-b77b-11d0-9da5-00c04fd65685}") IID_IMessage = ole.NewGUID("{00020307-0000-0000-C000-000000000046}") IID_IStream = ole.NewGUID("{0000000C-0000-0000-C000-000000000046}") modole32, _ = syscall.LoadDLL("ole32.dll") pCreateStreamOnHGlobal, _ = modole32.FindProc("CreateStreamOnHGlobal") pGetHGlobalFromStream, _ = modole32.FindProc("GetHGlobalFromStream") pCoCreateInstance, _ = modole32.FindProc("CoCreateInstance") modmapi32, _ = syscall.LoadDLL("mapi32.dll") pMAPIInitialize, _ = modmapi32.FindProc("MAPIInitialize") pMAPILogonEx, _ = modmapi32.FindProc("MAPILogonEx") modkernel32, _ = syscall.LoadDLL("kernel32.dll") pGlobalLock, _ = modkernel32.FindProc("GlobalLock") pGlobalUnlock, _ = modkernel32.FindProc("GlobalUnlock") ) // http://msdn2.microsoft.com/en-us/library/bb905202.aspx type IConverterSession struct { ole.IUnknown } type IConverterSessionVtbl struct { ole.IUnknownVtbl SetAdrBook uintptr SetEncoding uintptr PlaceHolder1 uintptr MIMEToMAPI uintptr MAPIToMIMEStm uintptr PlaceHolder2 uintptr PlaceHolder3 uintptr PlaceHolder4 uintptr SetTextWrapping uintptr SetSaveFormat uintptr PlaceHolder5 uintptr SetCharset uintptr } func (v *IConverterSession) VTable() *IConverterSessionVtbl { return (*IConverterSessionVtbl)(unsafe.Pointer(v.RawVTable)) } func (v *IConverterSession) SetEncoding(et uint32) (err error) { hr, _, _ := syscall.Syscall( v.VTable().SetEncoding, 2, uintptr(unsafe.Pointer(v)), uintptr(et), 0) if hr != 0 { err = ole.NewError(hr) fmt.Println(err) } return } func (v *IConverterSession) SetSaveFormat(et uint32) (err error) { hr, _, _ := syscall.Syscall( v.VTable().SetSaveFormat, 2, uintptr(unsafe.Pointer(v)), uintptr(et), 0) if hr != 0 { err = ole.NewError(hr) fmt.Println(err) } return } func (v *IConverterSession) SetTextWrapping(wrap bool, width uint32) (err error) { var wrapIt uint32 = 0 if wrap { wrapIt = 1 } hr, _, _ := syscall.Syscall( v.VTable().SetTextWrapping, 3, uintptr(unsafe.Pointer(v)), uintptr(wrapIt), uintptr(width)) if hr != 0 { err = ole.NewError(hr) fmt.Println(err) } return } func (v *IConverterSession) MAPIToMIMEStm(msg *ole.IDispatch, stm *IStream, flags uint32) (err error) { hr, _, _ := syscall.Syscall6( v.VTable().MAPIToMIMEStm, 4, uintptr(unsafe.Pointer(v)), uintptr(unsafe.Pointer(msg)), uintptr(unsafe.Pointer(stm)), uintptr(flags), 0, 0) if hr != 0 { err = ole.NewError(hr) fmt.Println(hr, "Error:", err) } return } func (v *IConverterSession) SetAdrBook(ab *ole.IUnknown) (err error) { hr, _, _ := syscall.Syscall( v.VTable().SetAdrBook, 2, uintptr(unsafe.Pointer(v)), uintptr(unsafe.Pointer(ab)), 0) if hr != 0 { err = ole.NewError(hr) fmt.Println(hr, "Error:", err) } return } type IStream struct { ole.IUnknown } type IStreamVtbl struct { ole.IUnknownVtbl Read uintptr Write uintptr Seek uintptr SetSize uintptr CopyTo uintptr Commit uintptr Revert uintptr LockRegion uintptr UnlockRegion uintptr Stat uintptr Clone uintptr } func (v *IStream) VTable() *IStreamVtbl { return (*IStreamVtbl)(unsafe.Pointer(v.RawVTable)) } func (v *IStream) Seek(move int32, origin uint32) (pos uint64, err error) { hr, _, _ := syscall.Syscall6( v.VTable().Seek, 5, uintptr(unsafe.Pointer(v)), 0, 0, uintptr(origin), uintptr(unsafe.Pointer(&pos)), 0) if hr != 0 { err = ole.NewError(hr) } return } func (v *IStream) Write(buf []byte) (written uint64, err error) { hr, _, _ := syscall.Syscall6( v.VTable().Write, 4, uintptr(unsafe.Pointer(v)), uintptr(unsafe.Pointer(&buf)), uintptr(len(buf)), uintptr(unsafe.Pointer(&written)), 0, 0) if hr != 0 { err = ole.NewError(hr) } return } type IMAPISession struct { ole.IUnknown } type IMAPISessionVtbl struct { ole.IUnknownVtbl GetLastError uintptr GetMsgStoresTable uintptr OpenMsgStore uintptr OpenAddressBook uintptr OpenProfileSection uintptr GetStatusTable uintptr OpenEntry uintptr CompareEntryIDs uintptr Advise uintptr Unadvise uintptr MessageOptions uintptr QueryDefaultMessageOpt uintptr EnumAdrTypes uintptr QueryIdentity uintptr Logoff uintptr SetDefaultStore uintptr AdminServices uintptr ShowForm uintptr PrepareForm uintptr } func (v *IMAPISession) VTable() *IMAPISessionVtbl { return (*IMAPISessionVtbl)(unsafe.Pointer(v.RawVTable)) } func (v *IMAPISession) OpenAddressBook() (ab *ole.IUnknown, err error) { hr, _, _ := syscall.Syscall6( v.VTable().OpenAddressBook, 5, uintptr(unsafe.Pointer(v)), 0, 0, 0, uintptr(unsafe.Pointer(&ab)), 0) if hr != 0 { err = ole.NewError(hr) } return } func CreateConverterSession() (unk *IConverterSession, err error) { hr, _, _ := pCoCreateInstance.Call(uintptr(unsafe.Pointer(CLSID_IConverterSession)), 0, ole.CLSCTX_INPROC_SERVER, uintptr(unsafe.Pointer(IID_IConverterSession)), uintptr(unsafe.Pointer(&unk))) if hr != 0 { err = ole.NewError(hr) } return } func main() { ole.CoInitialize(0) pMAPIInitialize.Call(uintptr(0)) var sess *IMAPISession var flags uint32 = 0x00000020 // | 0x00000002 |0x00000001 // MAPI_EXTENDED | MAPI_NO_MAIL pMAPILogonEx.Call(uintptr(0), 0, 0, uintptr(flags), uintptr(unsafe.Pointer(&sess))) var converter *IConverterSession hr, _, _ := pCoCreateInstance.Call(uintptr(unsafe.Pointer(CLSID_IConverterSession)), 0, ole.CLSCTX_INPROC_SERVER, uintptr(unsafe.Pointer(IID_IConverterSession)), uintptr(unsafe.Pointer(&converter))) if hr != 0 { fmt.Println(ole.NewError(hr)) return } const ( SAVE_RFC1521 = 1 IET_QP = 3 CCSF_SMTP = 2 ) converter.SetSaveFormat(SAVE_RFC1521) converter.SetEncoding(IET_QP) converter.SetTextWrapping(true, 74) ab, err := sess.OpenAddressBook() if err != nil { fmt.Println(err) return } converter.SetAdrBook(ab) var stm *IStream hr, _, _ = pCreateStreamOnHGlobal.Call(uintptr(0), uintptr(0), uintptr(unsafe.Pointer(&stm))) if hr != 0 { fmt.Println(ole.NewError(hr)) return } unknown, _ := oleutil.CreateObject("Outlook.Application") outlook, _ := unknown.QueryInterface(ole.IID_IDispatch) ns := oleutil.MustCallMethod(outlook, "GetNamespace", "MAPI").ToIDispatch() folders := oleutil.MustGetProperty(ns, "Folders").ToIDispatch() nfolders := oleutil.MustGetProperty(folders, "Count").Value().(int32) for i := 1; i <= int(nfolders); i++ { item, err := oleutil.GetProperty(folders, "Item", i) if err != nil || item.VT != ole.VT_DISPATCH { fmt.Println(err) continue } if value, err := oleutil.GetProperty(item.ToIDispatch(), "Name"); err == nil { fmt.Println(i, value.Value()) } if value, err := oleutil.GetProperty(item.ToIDispatch(), "FolderPath"); err == nil { fmt.Println(i, value.Value()) } } folder := oleutil.MustCallMethod(ns, "GetDefaultFolder", 6).ToIDispatch() if folder != nil { if value, err := oleutil.GetProperty(folder, "Name"); err == nil { fmt.Println(value.Value()) } if value, err := oleutil.GetProperty(folder, "FolderPath"); err == nil { fmt.Println(value.Value()) } } contacts := oleutil.MustCallMethod(folder, "Items").ToIDispatch() count := oleutil.MustGetProperty(contacts, "Count").Value().(int32) fmt.Println(count, " items") fmt.Println(time.Now()) for i := 100000; i <= int(count); i++ { if i >= 100100{ break } item, err := oleutil.GetProperty(contacts, "Item", i) if err != nil || item.VT != ole.VT_DISPATCH { fmt.Println(err) continue } if value, err := oleutil.GetProperty(item.ToIDispatch(), "MessageClass"); err == nil { // mclass := value.Value().(string) // if mclass == "IPM.Note" { continue } fmt.Println(i, value.Value()) } if value, err := oleutil.GetProperty(item.ToIDispatch(), "Subject"); err == nil { fmt.Println(i, value.Value()) } value, err := oleutil.GetProperty(item.ToIDispatch(), "MAPIOBJECT") if err != nil { fmt.Println(err) continue } mobj := value.Value().(*ole.IUnknown) msg, err := mobj.QueryInterface(IID_IMessage) if err != nil { fmt.Println(err) continue } err = converter.MAPIToMIMEStm(msg, stm, CCSF_SMTP) if err != nil { fmt.Println(err) continue } size, err := stm.Seek(0, 1) if err != nil || size <= 0 { fmt.Println(err) continue } fmt.Println("Size:", size) var handle uintptr hr, _, _ := pGetHGlobalFromStream.Call(uintptr(unsafe.Pointer(stm)), uintptr(unsafe.Pointer(&handle))) if hr != 0 { fmt.Println(ole.NewError(hr)) continue } /* addr, _, _ := pGlobalLock.Call(handle) if addr == 0 { fmt.Println("Unable to GlobalLock") continue } buf := (*[1 << 30]byte)(unsafe.Pointer(uintptr(addr)))[0:size] fmt.Println(string(buf[0:1000])) pGlobalUnlock.Call(handle) */ //reset stm.Seek(0, 0) } // oleutil.MustCallMethod(outlook, "Quit") fmt.Println(time.Now()) }