ref: b3df5eac3f2ebcd868ebfccb096da350df1f13bc
dir: /main.go/
package main
import (
"bytes"
"crypto/md5"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"os/exec"
"regexp"
"sort"
"strings"
)
var (
httpClient = &http.Client{}
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)
}