بالاخره تمام شد
چند روز وقت گرفت
تمام اوقات فراغت اين چند روز را كار كردم
اولين برنامهام به زبان Go
احتمالاً شما نيز گرفتار دستيابي به ايميلهاي قديمي خود شدهايد
ايميلهايي كه از سالها پيش بايگاني شدهاند
از روزهايي كه با Outlook كار ميكرديم
تا سرويسهاي مختلف تحت وب
همه را در فايلهاي eml نگهداشته بودم
و هر بار كه دنبال ايميلي ميگشتم
زمان زيادي از دست ميرفت
تصميم گرفتم يك برنامه بنويسم
كه تمام ده هزار فايل موجود را دستهبندي كند
بر اساس ايميل فرستنده و گيرنده
زبان Go را گفتند خيلي سريع است
چند ساليست كه گوگل توسعه آن را آغاز كرده
جايي خواندم كه ده برابر سريعتر از زبانهاي موجود
بسيار شبيه C و جاوا بود
تصميم گرفتم تجربه كنم
خيلي دستورها را خلاصه كرده
و علامتهاي اضافي و بيكاربرد را پيراسته
قابليتهاي جديدي نيز افزوده
جالبترين امكانش
بازگرداندن چندين مقدار از يك تابع، تنها با يك دستور بازگشت (!)
اگر چه ابزاريست كه بيشتر براي نوشتن Crawlerها
و ابزارهاي سروري استفاده ميشود
ولي من در اولين تجربه خود
اين ابزار را با آن نوشتم
(نسخه غير فشرده)
كار كردن با آن آسان است
كافيست در پوشهاي قرار دهيد
كه تمام فايلهاي eml در آن قرار دارد
همه در يك پوشه باشند
برنامه را كه اجرا كنيد
براي هر نشاني و آدرس يك پوشه ميسازد
و تمام ايميلهاي مربوط به آن نشاني را
در همان پوشه
بر اساس تاريخ قرار ميدهد
نام فايلها را به تاريخ و ساعت
كه دسترسي آسان باشد
يك علامت R يا S هم در انتها
تا معلوم شود ارساليست يا دريافتي
و تمام
واقعاً سريع عمل كرد
من دقيقاً 10024 عدد فايل eml داشتم
از سال 2000 تا كنون
با حجم حدود 5 گيگابايت
از ياهو و جيميل و هاتميل هم در آن بود
و از سرورهاي محلي ديگر
خروجيهايي كه در تمام اين سالها گرفته
همه را در كمتر از 30 ثانيه دستهبندي كرد
براي دسترسي به فايلها هم
ميتوان از ابزارهاي خوبي مانند SysTools EML Viewer استفاده نمود
سورس برنامه اين است:
package main
import (
"io/ioutil"
"strings"
"time"
"os"
"io"
"strconv"
)
var mFld,mPlc string
var FldCnt,MovCnt int
func main() {
bLog("\r\n===\r\nExecuting at " + time.Now().Format("2006-01-02 15:04:05") + "\r\n")
mFld = "~MovedEmails " + time.Now().Format("2006-01-02")
mPlc = "AllMails " + time.Now().Format("2006-01-02")
files, _ := ioutil.ReadDir("./")
for _, f := range files {
if fName := f.Name(); fName[len(fName)-4:]==".eml" {
bLog("Get File: "+fName+"\r\n")
fPath := mFld + "/" + fName
if _, err := os.Stat(fPath); os.IsNotExist(err) {
fDate,fFrom,fTo := fRead(fName)
mProc(fName,fDate + "-R",fTo)
mProc(fName,fDate + "-S",fFrom)
mMove(fName)
MovCnt++
}else{
bLog("Aborted Because Exists!\r\n")
}
}
}
print("\nFinished: "+strconv.Itoa(MovCnt)+" Email Moved!\n")
bLog("\r\nAll Folder Created: "+strconv.Itoa(FldCnt))
bLog("\r\nAll Emails Moved: "+strconv.Itoa(MovCnt)+"\r\n")
bLog("\r\nFinished at " + time.Now().Format("2006-01-02 15:04:05") + "\r\n\r\n\r\n")
}
func fRead(fName string)(fDate,fFrom,fTo string) {
dat, err := ioutil.ReadFile(fName)
check(err)
fCon := string(dat)
fFrom = gPart(fCon,"From")
fTo = gPart(fCon,"To")
fDate = gPart(fCon,"Date")
bLog("From: "+fFrom+" To: "+fTo+" Date: "+fDate+"\r\n")
if pos := strings.Index(fTo,","); pos>-1 {
fTo = fTo[:pos]
}
if pos := strings.Index(fDate,","); pos>-1 {
fDate = strings.TrimSpace(fDate[pos+1:])
if pos = strings.Index(fDate,"("); pos>-1 {
fDate = strings.TrimSpace(fDate[:pos])
}
}
if fDate != "NotFound" {
fDate = cDate(fDate)
}
return fDate, fFrom, fTo
}
func check(e error) {
if e != nil {
//panic(e)
bLog("\r\n---\r\n" + e.Error() + "\r\n---\r\n")
}
}
func gPart(fText,pName string)(s string) {
s = "NotFound"
fStr := "\n" + pName + ": "
fText = "\n" + fText
pos := strings.Index(fText, fStr)
if pos<0 {
pos = strings.Index(fText, strings.ToLower(fStr))
}
if pos>-1 {
npos := strings.Index(fText[pos+1:],"\n")
s = fText[pos+len(fStr):pos+npos]
if pos=strings.Index(s,"<"); pos>-1 && strings.Index(s[pos:],">")>0 {
s = s[pos+1:pos+strings.Index(s[pos:],">")]
}
}
return strings.TrimSpace(s)
}
func cDate (t string) string {
var tForm string
bLog("Date Convert From: " +t)
if t[len(t)-1:]!="0" {
tForm = "2 Jan 2006 15:04:05 MST"
}else{
tForm = "2 Jan 2006 15:04:05 -0700"
if len(t)>26 {
t=t[:26]
}
if len(t)==24 {
t=t+"00"
}
}
bLog(" By Fromat: " +tForm)
dTime, err := time.Parse(tForm, t)
check(err)
rTime := strings.Replace(dTime.Format("2006-01-02-15:04:05"),":","",-1)
bLog(" To: " +rTime+ "\r\n")
return rTime
}
func mProc(AslName, FileDate, FolName string) {
if len(FolName)>0 {
if strings.Index(FolName,"undisclosed")>-1 {
return
}
chs := "=+\\/!&":;,\"?<"
for i:=0;i<len(chs);i++ {
FolName=strings.Replace(FolName,chs[i:i+1],"",-1)
}
FolName=strings.TrimSpace(FolName)
if _, err := os.Stat(mPlc); os.IsNotExist(err) {
os.Mkdir(mPlc,0777)
bLog("Make Root Folder: "+mPlc+"\r\n")
}
if _, err := os.Stat(mPlc + "/" + FolName); os.IsNotExist(err) {
os.Mkdir(mPlc + "/" + FolName,0777)
print("Email: "+FolName+"\n")
bLog("Make Folder: "+FolName+"\r\n")
FldCnt++
}
oPath := mPlc + "/" + FolName + "/" + FileDate
fPath := oPath + ".eml"
for i:=1;;i++ {
if _, err := os.Stat(fPath); err == nil {
fPath = oPath + "-" + strconv.Itoa(i) + ".eml"
}else{
break
}
}
in, err := os.Open(AslName)
check(err)
defer in.Close()
out, err := os.Create(fPath)
check(err)
io.Copy(out, in)
bLog("File Copied: "+AslName+" To: "+fPath+"\r\n")
}
}
func mMove(AslName string) {
if _, err := os.Stat(mFld); os.IsNotExist(err) {
os.Mkdir(mFld,0777)
bLog("Make Backup Folder: "+mFld+"\r\n")
}
fPath := mFld + "/" + AslName
if _, err := os.Stat(fPath); os.IsNotExist(err) {
os.Rename(AslName,fPath)
bLog("File Moved: "+AslName+"\r\n")
}
}
func bLog(payam string) {
lName := "eml Organizer.log"
f,err := os.OpenFile(lName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0660)
check(err)
defer f.Close()
f.WriteString(payam)
}
ميتوانيد از اين نشاني برداريد
يك مشكل مهم دراستفاده از زبان برنامهنويسي Go وجود دارد
براي ما البته
شركت توليدكننده آن
همه IPهاي داخل ايران را بسته است
فيلتر كرده يعني
و نميتوان به سادگي به كتابخانههاي آن دسترسي داشت
از همه بدتر
وقتي از github.com سورسهاي آماده را برميداري
خيليهايشان به بستههاي گوگل ارجاع دادهاند
كه باز نميشوند
و كامپايل نرمافزار را با مشكل روبهرو ميسازند
من براي نوشتن اين ابزار كوچك
فقط از كتابخانههاي پيشفرض Go استفاده كردم
به عنوان اديتور
از ميان چند برنامهاي كه تست نمودم
Zeus را از همه راحتتر يافتم
و با آن نوشتم
حالا كه چه؟!
اينكه اكنون ميتوانم سوابق تمام مكاتبات اينترنتي خود را مرور كنم
و اطلاعات مفيد و قابل استفاده را
باز استفاده نمايم!