package main import ( "bytes" "crypto/md5" "fmt" "io/ioutil" "log" "net/http" "os" "os/exec" "regexp" "sort" "strings" "time") var ( httpClient = &http.Client{Timeout: 5 * time.Second} base = "/mail/fs") func main() { home, err := os.UserHomeDir() if err != nil { log.Fatal(err) } faceBase := home + "/lib/face" outBase := faceBase + "/48x48x8" notFoundPath := faceBase + "/.notfound" ignorePath := faceBase + "/.ignorelist" dictPath := outBase + "/.dict" froms := map[string][md5.Size]byte{} fs, err := ioutil.ReadDir(base) if err != nil { log.Fatal(err) } for _, fsi := range fs { if !fsi.IsDir() { continue } msgsBase := base + "/" + fsi.Name() msgs, err := ioutil.ReadDir(msgsBase) if err != nil { log.Fatal(err) } for _, mi := range msgs { if !mi.IsDir() { continue } if from, err := ioutil.ReadFile(msgsBase + "/" + mi.Name() + "/from"); err != nil { log.Fatal(err) } else { f := strings.ToLower(string(from)) froms[f] = md5.Sum([]byte(f)) } } } if err = os.MkdirAll(outBase, 0700); err != nil { log.Fatal(err) } var ignoreList []*regexp.Regexp if s, err := ioutil.ReadFile(ignorePath); err == nil { for _, v := range strings.Split(string(s), "\n") { if v != "" { if r, err := regexp.Compile(v); err != nil { log.Fatalf("%s: %s", ignorePath, err) } else { ignoreList = append(ignoreList, r) } } } } notFound := make(map[string]struct{}) if s, err := ioutil.ReadFile(notFoundPath); err == nil { for _, v := range strings.Split(string(s), "\n") { if v != "" { notFound[v] = struct{}{} } } } dict := make(map[string]string) if s, err := ioutil.ReadFile(dictPath); err == nil { for _, v := range strings.Split(string(s), "\n") { if v != "" { parts := strings.Split(v, " ") dict[parts[0]] = parts[1] } } } numTotal := len(froms) i := 0 failed := 0 saved := 0 ignored := 0 progress := "" for f, h := range froms { hash := fmt.Sprintf("%x", h) imagePath := outBase + "/" + hash i++ clear := strings.Repeat("\x08", len(progress)) progress = fmt.Sprintf("%d/%d", i, numTotal) fmt.Printf("%s%s", clear, progress) var machineUser string if parts := strings.Split(f, "@"); len(parts) != 2 { failed++ continue } else { userParts := strings.Split(parts[0], "+") machineUser = fmt.Sprintf("%s/%s", parts[1], userParts[0]) skip := false for _, ignore := range ignoreList { if ignore.MatchString(machineUser) { ignored++ os.Remove(imagePath) delete(dict, machineUser) delete(notFound, machineUser) skip = true } } if skip { continue } if _, ok := dict[machineUser]; ok { continue } if _, ok := notFound[machineUser]; ok { continue } } url := fmt.Sprintf("http://gravatar.com/avatar/%s.jpg?s=48&d=404", hash) if res, err := httpClient.Get(url); err != nil { log.Fatal(err) } else if res.StatusCode != http.StatusOK { if res.StatusCode == http.StatusNotFound { notFound[machineUser] = struct{}{} } res.Body.Close() continue } else { b := new(bytes.Buffer) b.ReadFrom(res.Body) res.Body.Close() data := new(bytes.Buffer) cmd := exec.Command("/bin/jpg", "-c") cmd.Stdin = bytes.NewReader(b.Bytes()) cmd.Stdout = data if err = cmd.Run(); err != nil { data.Reset() cmd = exec.Command("/bin/png", "-c") cmd.Stdin = bytes.NewReader(b.Bytes()) cmd.Stdout = data err = cmd.Run() } if err != nil { failed++ } else if err = ioutil.WriteFile(imagePath, data.Bytes(), 0644); err != nil { log.Fatal(err) } else { dict[machineUser] = hash saved++ } } } if f, err := os.Create(notFoundPath); err != nil { log.Fatal(err) } else { var sorted []string for machineUser := range notFound { sorted = append(sorted, machineUser) } sort.Strings(sorted) for _, s := range sorted { fmt.Fprintf(f, "%s\n", s) } f.Close() } if f, err := os.Create(dictPath); err != nil { log.Fatal(err) } else { var sorted []string for machineUser := range dict { sorted = append(sorted, machineUser) } sort.Strings(sorted) for _, s := range sorted { fmt.Fprintf(f, "%s %s\n", s, dict[s]) } f.Close() } fmt.Printf("%s", strings.Repeat("\x08", len(progress))) fmt.Printf("%d addresses\n", numTotal) fmt.Printf("%d faces added\n", saved) fmt.Printf("%d failed to decode\n", failed) fmt.Printf("%d ignored\n", ignored)}
package main
import (
"bytes"
"crypto/md5"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"os/exec"
"regexp"
"sort"
"strings"
"time"
)
var (
httpClient = &http.Client{Timeout: 5 * time.Second}
base = "/mail/fs"
)
func main() {
home, err := os.UserHomeDir()
if err != nil {
log.Fatal(err)
}
faceBase := home + "/lib/face"
outBase := faceBase + "/48x48x8"
notFoundPath := faceBase + "/.notfound"
ignorePath := faceBase + "/.ignorelist"
dictPath := outBase + "/.dict"
froms := map[string][md5.Size]byte{}
fs, err := ioutil.ReadDir(base)
if err != nil {
log.Fatal(err)
}
for _, fsi := range fs {
if !fsi.IsDir() {
continue
}
msgsBase := base + "/" + fsi.Name()
msgs, err := ioutil.ReadDir(msgsBase)
if err != nil {
log.Fatal(err)
}
for _, mi := range msgs {
if !mi.IsDir() {
continue
}
if from, err := ioutil.ReadFile(msgsBase + "/" + mi.Name() + "/from"); err != nil {
log.Fatal(err)
} else {
f := strings.ToLower(string(from))
froms[f] = md5.Sum([]byte(f))
}
}
}
if err = os.MkdirAll(outBase, 0700); err != nil {
log.Fatal(err)
}
var ignoreList []*regexp.Regexp
if s, err := ioutil.ReadFile(ignorePath); err == nil {
for _, v := range strings.Split(string(s), "\n") {
if v != "" {
if r, err := regexp.Compile(v); err != nil {
log.Fatalf("%s: %s", ignorePath, err)
} else {
ignoreList = append(ignoreList, r)
}
}
}
}
notFound := make(map[string]struct{})
if s, err := ioutil.ReadFile(notFoundPath); err == nil {
for _, v := range strings.Split(string(s), "\n") {
if v != "" {
notFound[v] = struct{}{}
}
}
}
dict := make(map[string]string)
if s, err := ioutil.ReadFile(dictPath); err == nil {
for _, v := range strings.Split(string(s), "\n") {
if v != "" {
parts := strings.Split(v, " ")
dict[parts[0]] = parts[1]
}
}
}
numTotal := len(froms)
i := 0
failed := 0
saved := 0
ignored := 0
progress := ""
for f, h := range froms {
hash := fmt.Sprintf("%x", h)
imagePath := outBase + "/" + hash
i++
clear := strings.Repeat("\x08", len(progress))
progress = fmt.Sprintf("%d/%d", i, numTotal)
fmt.Printf("%s%s", clear, progress)
var machineUser string
if parts := strings.Split(f, "@"); len(parts) != 2 {
failed++
continue
} else {
userParts := strings.Split(parts[0], "+")
machineUser = fmt.Sprintf("%s/%s", parts[1], userParts[0])
skip := false
for _, ignore := range ignoreList {
if ignore.MatchString(machineUser) {
ignored++
os.Remove(imagePath)
delete(dict, machineUser)
delete(notFound, machineUser)
skip = true
}
}
if skip {
continue
}
if _, ok := dict[machineUser]; ok {
continue
}
if _, ok := notFound[machineUser]; ok {
continue
}
}
url := fmt.Sprintf("http://gravatar.com/avatar/%s.jpg?s=48&d=404", hash)
if res, err := httpClient.Get(url); err != nil {
log.Fatal(err)
} else if res.StatusCode != http.StatusOK {
if res.StatusCode == http.StatusNotFound {
notFound[machineUser] = struct{}{}
}
res.Body.Close()
continue
} else {
b := new(bytes.Buffer)
b.ReadFrom(res.Body)
res.Body.Close()
data := new(bytes.Buffer)
cmd := exec.Command("/bin/jpg", "-c")
cmd.Stdin = bytes.NewReader(b.Bytes())
cmd.Stdout = data
if err = cmd.Run(); err != nil {
data.Reset()
cmd = exec.Command("/bin/png", "-c")
cmd.Stdin = bytes.NewReader(b.Bytes())
cmd.Stdout = data
err = cmd.Run()
}
if err != nil {
failed++
} else if err = ioutil.WriteFile(imagePath, data.Bytes(), 0644); err != nil {
log.Fatal(err)
} else {
dict[machineUser] = hash
saved++
}
}
}
if f, err := os.Create(notFoundPath); err != nil {
log.Fatal(err)
} else {
var sorted []string
for machineUser := range notFound {
sorted = append(sorted, machineUser)
}
sort.Strings(sorted)
for _, s := range sorted {
fmt.Fprintf(f, "%s\n", s)
}
f.Close()
}
if f, err := os.Create(dictPath); err != nil {
log.Fatal(err)
} else {
var sorted []string
for machineUser := range dict {
sorted = append(sorted, machineUser)
}
sort.Strings(sorted)
for _, s := range sorted {
fmt.Fprintf(f, "%s %s\n", s, dict[s])
}
f.Close()
}
fmt.Printf("%s", strings.Repeat("\x08", len(progress)))
fmt.Printf("%d addresses\n", numTotal)
fmt.Printf("%d faces added\n", saved)
fmt.Printf("%d failed to decode\n", failed)
fmt.Printf("%d ignored\n", ignored)
}