-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathadd.go
More file actions
181 lines (159 loc) · 4.85 KB
/
add.go
File metadata and controls
181 lines (159 loc) · 4.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package main
import (
"fmt"
"log"
"math"
"os"
"reflect"
"regexp"
"strconv"
"time"
"github.com/bcgraham/tsumtsum/external/line"
)
type AddCommand struct {
SourceInput string `short:"s" long:"source" default:"" description:"source of user IDs to be added to contact list. Tries to parse as a URL; if this fails, will assume it is a file."`
Limit int `short:"l" long:"limit" default:"500" description:"how many contacts to add before stopping (defaults to 500; anything more than 800 will probably result in a tempban)"`
}
var addCommand AddCommand
func (x *AddCommand) Execute(args []string) error {
if common.User == "LINELOGIN" {
fmt.Print("You have to type your own LINE login after the \"-u=\" - see how you passed \r\nin LINELOGIN? That's just placeholder text for your username.\n")
os.Exit(1)
}
session := MustNewSession(common.User, common.Device, common.ReportingServer)
if x.SourceInput == "" {
x.SourceInput = session.reportingServer.String()
}
err := session.LoadStrangers(x.SourceInput)
if err != nil {
log.Fatalf("Could not load strangers: %v", err)
}
t := time.Now()
found, err := session.AddStrangers(x.Limit)
fmt.Printf("\n\nElapsed time: %v. Averaged %.0f contacts per minute.\n", time.Since(t), avg(found, time.Since(t)))
if err != nil {
log.Print(err.Error())
return err
}
return nil
}
func init() {
if _, err := parser.AddCommand("add",
"Add strangers",
"The add command adds contacts from a source to your contact list.",
&addCommand); err != nil {
log.Fatal(err)
}
}
func (s *Session) AddContact(id string) (mid string, err error) {
AddContactFunc := (*line.TalkServiceClient).FindAndAddContactsByUserid
if midMatcher.MatchString(id) {
AddContactFunc = (*line.TalkServiceClient).FindAndAddContactsByMid
}
r, err := AddContactFunc(s.client, <-s.reqSeq, id)
if err != nil {
// http response code 400 basically means
// reconnect. not sure what causes it.
if err.Error() == "HTTP Response code: 400" {
s.logger.Printf("Got error \"%v\"\n.", err.Error())
err = s.Rebuild()
if err != nil {
return mid, err
}
r, err = AddContactFunc(s.client, <-s.reqSeq, id)
}
if err != nil {
if isTransportError(err) {
return mid, err
}
if isContactsListFull(err) {
msg := "\nCan't continue adding contacts. Your contact list is probably full (5000 contacts). Sleeping for ten minutes, then will resume.\n"
s.logger.Print(msg)
return mid, err
}
if isAbuse(err) {
s.logger.Print("Your usage has been flagged as abuse and you can't presently add friends. This is almost certainly from trying to add too many friends. This is usually a temporary ban that lasts between 12 and 24 hours, but they last longer if you're a repeat offender.\n")
return mid, err
}
}
}
var userID string
if !isMid(id) {
userID = id
if contact, ok := r[id]; ok {
mid = contact.GetMid()
s.strangers[userID] = mid
}
} else {
mid = id
}
err = s.SendReport(Report{
Submitter: s.username,
UserID: userID,
MID: mid,
Type: search,
})
if err != nil {
log.Printf("error sending search result: %v\n", err)
}
return mid, err
}
func (s *Session) AddStrangers(limit int) (found int, err error) {
max := limit
if len(s.strangers) < max {
max = len(s.strangers)
}
var count int
for id := range s.strangers {
if count >= max {
break
}
if !s.isNewID(id) {
continue
}
mid, err := s.AddContact(id)
if err != nil {
if isAbuse(err) || isContactsListFull(err) {
return found, err
}
s.logger.Printf("error adding contact: %v\n", err)
}
count++
if mid != "" {
found++
}
addProgress(count, max, found)
}
return found, nil
}
var midMatcher *regexp.Regexp
func init() {
midMatcher = regexp.MustCompile("^u[a-fA-F0-9]{32}$")
}
func isMid(id string) bool {
return midMatcher.MatchString(id)
}
func avg(found int, d time.Duration) float64 {
x := float64(found) * (float64(time.Minute) / float64(d))
if math.IsNaN(x) {
return 0
}
return x
}
func isTransportError(err error) bool {
return reflect.TypeOf(err).String() == "*thrift.tTransportException"
}
func isContactsListFull(err error) bool {
return reflect.TypeOf(err).String() == "*line.TalkException" && err.(*line.TalkException).GetCode() == line.ErrorCode_INVALID_STATE && err.(*line.TalkException).GetReason()[:18] != "Cannot find userid"
}
func isAbuse(err error) bool {
return reflect.TypeOf(err).String() == "*line.TalkException" && err.(*line.TalkException).GetCode() == line.ErrorCode_ABUSE_BLOCK
}
func addProgress(count, max, found int) {
printProgress(prog{
str: "%.2f%% completed. (%" + strconv.Itoa(len(strconv.Itoa(max))) + "d/%d) %" + strconv.Itoa(len(strconv.Itoa(max))) + "d of %" + strconv.Itoa(len(strconv.Itoa(max))) + "d found (%.2f%%).",
args: []interface{}{
100 * float64(count) / float64(max), count, max, found, count, 100 * float64(found) / float64(count),
},
})
}