apps / sms / bot /
Newer Older
342 lines | 12.057kb
initial commit
admin cloud-section (root) authored on 2016-12-10
1
#!/usr/bin/perl
2

            
3
use strict;
4
use warnings;
5

            
6
use DBI;
7
use POSIX qw/ceil strftime/;
changement de moyen de commu...
seb authored on 2019-12-16
8
use HiPi::Huawei::E3531;
9
use HiPi::Huawei::Errors;
initial commit
admin cloud-section (root) authored on 2016-12-10
10

            
11
use open ':utf8';
12
use open ':std';
13
use utf8;
changement de moyen de commu...
seb authored on 2019-12-16
14

            
fix problème avec dequeue co...
Sébastien authored on 2019-12-22
15
#use Data::Dumper;
initial commit
admin cloud-section (root) authored on 2016-12-10
16

            
17
use threads;
18
use threads::shared;
19
use Thread::Queue;
changement de moyen de commu...
seb authored on 2019-12-16
20
use Thread::Semaphore;
initial commit
admin cloud-section (root) authored on 2016-12-10
21

            
changement de moyen de commu...
seb authored on 2019-12-16
22
my $scriptconf = $0;
initial commit
admin cloud-section (root) authored on 2016-12-10
23
$scriptconf =~ s/\.pl$//;
24
$scriptconf =~ s/$/.conf/;
25
if (-r $scriptconf) {
26
    package cfg;
27
    unless (my $return = do $scriptconf) {
28
        warn "couldn't parse $scriptconf: $@" if $@;
29
        warn "couldn't do $scriptconf: $!"    unless defined $return;
30
        warn "couldn't run $scriptconf"       unless $return;
31
    }
32
}
33
else {
34
    print "pas de config\n";
35
    exit;
36
}
37

            
38
$SIG{INT}=\&terminate;
39

            
changement de moyen de commu...
seb authored on 2019-12-16
40
my $inbox_sms_queue = Thread::Queue->new;
41
my $outbox_sms_queue = Thread::Queue->new;
initial commit
admin cloud-section (root) authored on 2016-12-10
42
my $mail_queue = Thread::Queue->new;
43

            
changement de moyen de commu...
seb authored on 2019-12-16
44
my $mutex = Thread::Semaphore->new();
45
STDERR->autoflush();
initial commit
admin cloud-section (root) authored on 2016-12-10
46

            
changement de moyen de commu...
seb authored on 2019-12-16
47
my $mail = threads->new(\&send_mail);
initial commit
admin cloud-section (root) authored on 2016-12-10
48

            
changement de moyen de commu...
seb authored on 2019-12-16
49
my $inbox_sms = threads->new(\&inbox_sms_parse);
initial commit
admin cloud-section (root) authored on 2016-12-10
50

            
changement de moyen de commu...
seb authored on 2019-12-16
51
my $outbox_sms = threads->new(\&hilink_send_sms);
initial commit
admin cloud-section (root) authored on 2016-12-10
52

            
changement de moyen de commu...
seb authored on 2019-12-16
53
my $hlink = HiPi::Huawei::E3531->new();
initial commit
admin cloud-section (root) authored on 2016-12-10
54

            
55
sub log_bot {
changement de moyen de commu...
seb authored on 2019-12-16
56
    $mutex->down();
57
    print STDERR sprintf("%s\n", shift);
58
    $mutex->up();
initial commit
admin cloud-section (root) authored on 2016-12-10
59
}
60

            
61
sub terminate () {
changement de moyen de commu...
seb authored on 2019-12-16
62
    log_bot($mail_queue->pending() . " mails en attente d'envoi !") if ($mail_queue->pending() > 0);
63
    $mail->exit();
64
    log_bot($inbox_sms_queue->pending() . " SMS en attente de traitement !") if ($inbox_sms_queue->pending() > 0);
65
    $inbox_sms->exit();
66
    log_bot($outbox_sms_queue->pending() . " SMS en attente d'envoi !") if ($outbox_sms_queue->pending() > 0);
67
    $outbox_sms->exit();
68
    log_bot("arrêt");
initial commit
admin cloud-section (root) authored on 2016-12-10
69
    exit 0;
70
}
71

            
72
sub sql_request ($) {
changement de moyen de commu...
seb authored on 2019-12-16
73
    my $msg = shift;
initial commit
admin cloud-section (root) authored on 2016-12-10
74
    my @result;
75
    my $dbh = DBI->connect($cfg::config{db}->{driver}, $cfg::config{db}->{user}, $cfg::config{db}->{password}, {'RaiseError' => 1});
76
    $dbh->{'mysql_enable_utf8'} = 1;
77
    $dbh->do(qq{SET NAMES "utf8"});
changement de moyen de commu...
seb authored on 2019-12-16
78
    my $sth = $dbh->prepare($msg);
initial commit
admin cloud-section (root) authored on 2016-12-10
79
    $sth->execute();
80
    if (defined($sth->{NUM_OF_FIELDS})) {
81
        while (my $ref = $sth->fetchrow_hashref()) {
82
            push @result, $ref;
83
        }
84
    }
85
    $sth->finish();
86
    $dbh->disconnect();
87
    return @result;
88
}
89

            
90
sub massive_send_sms {
changement de moyen de commu...
seb authored on 2019-12-16
91
    my $msg = shift;
92
    if ($outbox_sms_queue->pending() > 0) {
93
        $outbox_sms_queue->insert(0, [$msg->{Phone}, "un envoi massif est déjà en cours, lancé par " . $cfg::config{last_sender} . ", reste " . $outbox_sms_queue->pending() . ", annulation"]);
simplification table + répon...
admin cloud-section (root) authored on 2019-03-17
94
        return;
95
    }
changement de moyen de commu...
seb authored on 2019-12-16
96
    $cfg::config{last_sender} = $msg->{PhoneOwner};
97
    my @results = sql_request("SELECT phone, firstname, gender FROM " . $cfg::config{table} . " WHERE " . $cfg::config{group_prefix} . $msg->{groupe} . " > '0'");
simplification table + répon...
admin cloud-section (root) authored on 2019-03-17
98
    my $qty = scalar(@results);
99
    my $start_msg = "envoi de " . $qty . " SMS (fin prévue entre ". strftime("%H:%M", localtime(time() + $qty * 60)) . " et " . strftime("%H:%M", localtime(time() + $qty * 90)) . ")";
changement de moyen de commu...
seb authored on 2019-12-16
100
    $outbox_sms_queue->enqueue([$msg->{Phone}, $start_msg]);
simplification table + répon...
admin cloud-section (root) authored on 2019-03-17
101
    foreach my $contact (@results) {
102
        $contact->{phone} =~ s/[\s\.]//g;
changement de moyen de commu...
seb authored on 2019-12-16
103
        $_ = $msg->{Content};
simplification table + répon...
admin cloud-section (root) authored on 2019-03-17
104
        s/\@prénom/$contact->{firstname}/g;
105
        if ($contact->{gender} eq 'F') {
106
            s/\@\(\s*(\w+)\s*,\s*\w+\s*\)/$1/g;
réponse prioritaire au ping ...
admin cloud-section (root) authored on 2018-11-25
107
        }
simplification table + répon...
admin cloud-section (root) authored on 2019-03-17
108
        else {
109
            s/\@\(\s*\w+\s*,\s*(\w+)\s*\)/$1/g;
initial commit
admin cloud-section (root) authored on 2016-12-10
110
        }
changement de moyen de commu...
seb authored on 2019-12-16
111
        $outbox_sms_queue->enqueue([$contact->{phone}, $_])
initial commit
admin cloud-section (root) authored on 2016-12-10
112
    }
changement de moyen de commu...
seb authored on 2019-12-16
113
    $outbox_sms_queue->enqueue([$msg->{Phone}, "envoi des SMS terminé !"]);
initial commit
admin cloud-section (root) authored on 2016-12-10
114
}
115

            
changement de moyen de commu...
seb authored on 2019-12-16
116
sub send_mail {
fix problème avec dequeue co...
Sébastien authored on 2019-12-22
117
    while (1) {
118
        my $msg = $mail_queue->dequeue_timed(10, 1);
119
        next if ! defined $msg;
changement de moyen de commu...
seb authored on 2019-12-16
120
        defined($msg->{to}) or $msg->{to} = $cfg::config{mail};
121
        open(MAIL, "|msmtp $msg->{to}");
122
        print MAIL "Subject: $msg->{Subject}\n";
123
        print MAIL "Reply-To: $msg->{Email}\n" if ($msg->{Email} ne '');
initial commit
admin cloud-section (root) authored on 2016-12-10
124

            
changement de moyen de commu...
seb authored on 2019-12-16
125
        print MAIL "$msg->{Content}\n";
initial commit
admin cloud-section (root) authored on 2016-12-10
126
        close(MAIL);
changement de moyen de commu...
seb authored on 2019-12-16
127
        log_bot("mail envoyé à $msg->{to}");
initial commit
admin cloud-section (root) authored on 2016-12-10
128
    }
129
}
130

            
131
sub wait_open_time ($$) {
132
    my ($close_hour, $open_hour) = @_;
fix: heures silencieuses
admin cloud-section (root) authored on 2018-11-25
133
    my @lt = localtime;
134
    while ($lt[2] >= $close_hour or $lt[2] <= $open_hour) {
initial commit
admin cloud-section (root) authored on 2016-12-10
135
        sleep 1800;
136
    }
137
}
138

            
changement de moyen de commu...
seb authored on 2019-12-16
139
sub hilink_send_sms {
140
    my $sendbox = HiPi::Huawei::E3531->new();
141
    while (1) {
142
        my $sms = $outbox_sms_queue->dequeue_timed(10, 1);
143
        next if ! defined $sms;
simplification table + répon...
admin cloud-section (root) authored on 2019-03-17
144
        wait_open_time($cfg::config{close_hour}, $cfg::config{begin_hour}); # pas d'envoi entre 21h et 8h
changement de moyen de commu...
seb authored on 2019-12-16
145

            
146
        if ($sendbox->{code}) {
147
            log_bot('sendbox new: ' . HiPi::Huawei::Errors->get_error_message($sendbox->{code}));
148
        }
149
        else {
150
            my $reponse = $sendbox->send_sms($$sms[0], , $$sms[1]);
151
            if ($reponse->{code}) {
152
                log_bot('send_sms: ' . HiPi::Huawei::Errors->get_error_message($reponse->{code}));
153
            }
154

            
155
            log_bot("envoi à $$sms[0] : $$sms[1]");
156
        }
157
        sleep 60 + int(rand(30));
initial commit
admin cloud-section (root) authored on 2016-12-10
158
    }
changement de moyen de commu...
seb authored on 2019-12-16
159
    log_bot('fin du thread outbox_sms');
initial commit
admin cloud-section (root) authored on 2016-12-10
160
}
161

            
162
sub is_authorized {
changement de moyen de commu...
seb authored on 2019-12-16
163
    my ($msg) = @_;
164
    my @results = sql_request("SELECT * FROM $cfg::config{table} WHERE phone = '$msg->{Phone}'");
sms/action: envoi du mail de...
admin cloud-section (root) authored on 2017-02-17
165
    if (scalar(@results) == 1) {
simplification table + répon...
admin cloud-section (root) authored on 2019-03-17
166
        my $_results = $results[0];
167
        foreach my $column (keys(%$_results)) {
168
            if ($column =~ /^$cfg::config{group_prefix}/) {
169
                if ($results[0]->{$column} == 2) {
changement de moyen de commu...
seb authored on 2019-12-16
170
                    $msg->{address} = $results[0]->{address};
simplification table + répon...
admin cloud-section (root) authored on 2019-03-17
171
                    return 1; # true
172
                }
173
            }
174
        }
175
        return 0; # false
sms/action: envoi du mail de...
admin cloud-section (root) authored on 2017-02-17
176
    }
177
    else {
simplification table + répon...
admin cloud-section (root) authored on 2019-03-17
178
        return 0; # false
sms/action: envoi du mail de...
admin cloud-section (root) authored on 2017-02-17
179
    }
initial commit
admin cloud-section (root) authored on 2016-12-10
180
}
181

            
182
sub authorized_on_table {
changement de moyen de commu...
seb authored on 2019-12-16
183
    my %msg = @_;
184
    my $table_name = $cfg::config{group_prefix} . $msg{groupe};
185
    my @results = sql_request("SELECT * FROM $cfg::config{table} WHERE phone = '$msg{id}'");
simplification table + répon...
admin cloud-section (root) authored on 2019-03-17
186
    if (scalar(@results) == 1) {
187
        if (! defined($results[0]->{$table_name})) {
changement de moyen de commu...
seb authored on 2019-12-16
188
            $msg{error} = "le groupe $msg{groupe} n'existe pas";
189
            $outbox_sms_queue->insert(0, [$msg{id}, $msg{error}]);
simplification table + répon...
admin cloud-section (root) authored on 2019-03-17
190
            return 0; # false
initial commit
admin cloud-section (root) authored on 2016-12-10
191
        }
192
    }
changement de moyen de commu...
seb authored on 2019-12-16
193
    @results = sql_request("SELECT $table_name FROM $cfg::config{table} WHERE phone = '$msg{id}'");
simplification table + répon...
admin cloud-section (root) authored on 2019-03-17
194
    if (scalar(@results) == 1) {
195
        if ($results[0]->{$table_name} != 2) {
changement de moyen de commu...
seb authored on 2019-12-16
196
            $msg{error} = "désolé, écrire au groupe $msg{groupe} n'est pas autorisé pour toi";
197
            $outbox_sms_queue->insert(0, [$msg{id}, $msg{error}]);
simplification table + répon...
admin cloud-section (root) authored on 2019-03-17
198
            return 0; # false
initial commit
admin cloud-section (root) authored on 2016-12-10
199
        }
simplification table + répon...
admin cloud-section (root) authored on 2019-03-17
200
        else {
201
            return 1; # true
initial commit
admin cloud-section (root) authored on 2016-12-10
202
        }
203
    }
204
}
205

            
206
sub react_on_message {
changement de moyen de commu...
seb authored on 2019-12-16
207
    my ($hashref , $msg) = @_;
initial commit
admin cloud-section (root) authored on 2016-12-10
208
    for my $regex (keys(%$hashref)) {
changement de moyen de commu...
seb authored on 2019-12-16
209
        if ($msg->{Content} =~ m/$regex/i) {
210
            $msg->{Content} =~ s/$regex//i;
initial commit
admin cloud-section (root) authored on 2016-12-10
211
            $hashref->{$regex}();
212
            return 1; # true
213
        }
214
    }
215
    return 0; # false
216
}
217

            
changement de moyen de commu...
seb authored on 2019-12-16
218
sub inbox_sms_parse {
fix problème avec dequeue co...
Sébastien authored on 2019-12-22
219
    while (1) {
220
        my $msg = $inbox_sms_queue->dequeue_timed(10, 1);
221
        next if ! defined $msg;
signal d'envoi immédiat du m...
admin cloud-section (root) authored on 2017-02-18
222

            
initial commit
admin cloud-section (root) authored on 2016-12-10
223
        my %part_from_user = (
passage des regex dans le fi...
admin cloud-section (root) authored on 2017-02-17
224
            $cfg::user{"message de groupe"} => sub {
changement de moyen de commu...
seb authored on 2019-12-16
225
                $msg->{groupe} = lc $1;
226
                if (authorized_on_table(groupe => $msg->{groupe}, id => $msg->{Phone})) {
227
                    &massive_send_sms(\%$msg);
simplification table + répon...
admin cloud-section (root) authored on 2019-03-17
228
                }
initial commit
admin cloud-section (root) authored on 2016-12-10
229
            },
passage des regex dans le fi...
admin cloud-section (root) authored on 2017-02-17
230
            $cfg::user{"message pour un destinataire"} => sub {
changement de moyen de commu...
seb authored on 2019-12-16
231
                $outbox_sms_queue->enqueue([$1, $msg->{Content}]);
initial commit
admin cloud-section (root) authored on 2016-12-10
232
            },
passage des regex dans le fi...
admin cloud-section (root) authored on 2017-02-17
233
            $cfg::user{"ping"} => sub {
changement de moyen de commu...
seb authored on 2019-12-16
234
                my $envoi_en_cours = '';
235
                if ($outbox_sms_queue->pending() > 0) {
fix problème avec dequeue co...
Sébastien authored on 2019-12-22
236
#                    for (my $queue_id = $outbox_sms_queue->pending(); $queue_id >= 0; $queue_id--) {
237
#                        log_bot(Dumper($outbox_sms_queue->peek($queue_id)));
238
#                    }
changement de moyen de commu...
seb authored on 2019-12-16
239
                    $envoi_en_cours = "\nenvoi en cours de traitement (reste " . $outbox_sms_queue->pending() . ") ";
240
                    $envoi_en_cours .= "par $cfg::config{last_sender}" if defined($cfg::config{last_sender});
sms/action: envoi du mail de...
admin cloud-section (root) authored on 2017-02-17
241
                }
changement de moyen de commu...
seb authored on 2019-12-16
242
                log_bot("envoi d'un pong à $msg->{Phone} $msg->{PhoneOwner} $envoi_en_cours");
243
                $outbox_sms_queue->insert(0, [$msg->{Phone}, "pong" . $envoi_en_cours]);
sms/action: envoi du mail de...
admin cloud-section (root) authored on 2017-02-17
244
            },
initial commit
admin cloud-section (root) authored on 2016-12-10
245
        );
246

            
changement de moyen de commu...
seb authored on 2019-12-16
247
        $msg->{Phone} =~ s/^\+33/0/;
248
        $msg->{Email} = '';
249

            
250
        my @results = sql_request("SELECT * FROM " . $cfg::config{table} . " WHERE phone = '$msg->{Phone}'");
251
        my $number_of_candidates = @results;
252
        $number_of_candidates == 0 and return;
253
        $msg->{PhoneOwner} = '(';
254
        foreach (@results) {
255
            $msg->{PhoneOwner} .= "$_->{firstname} $_->{lastname}";
256
            --$number_of_candidates > 0 and $msg->{PhoneOwner} .= ' ou ';
257
            $msg->{Email} = $_->{email};
initial commit
admin cloud-section (root) authored on 2016-12-10
258
        }
changement de moyen de commu...
seb authored on 2019-12-16
259
        $msg->{PhoneOwner} .= ')';
260
        $msg->{Subject} = "SMS recu de $msg->{Phone} $msg->{PhoneOwner}";
261

            
262
        if (defined $msg->{Phone} and !(is_authorized(\%$msg) and react_on_message(\%part_from_user, \%$msg))) {
263
            log_bot("message de $msg->{Phone} $msg->{PhoneOwner}");
264
            $mail_queue->enqueue(\%$msg);
initial commit
admin cloud-section (root) authored on 2016-12-10
265
        }
266

            
changement de moyen de commu...
seb authored on 2019-12-16
267
        undef $msg;
initial commit
admin cloud-section (root) authored on 2016-12-10
268
    }
269
}
270

            
changement de moyen de commu...
seb authored on 2019-12-16
271
$inbox_sms->detach;    # gère la file des événements produits par GTalkSMS
272
log_bot("inbox thread ok");
273
$outbox_sms->detach;   # gère la file des envois de SMS par GTalkSMS
274
log_bot("outbox thread ok");
275
$mail->detach;         # gère la file des mails
276
log_bot("mail thread ok");
initial commit
admin cloud-section (root) authored on 2016-12-10
277

            
changement de moyen de commu...
seb authored on 2019-12-16
278
my $loop = 0;
279
log_bot("robot prêt");
280
while ( 1 ) {
initial commit
admin cloud-section (root) authored on 2016-12-10
281

            
changement de moyen de commu...
seb authored on 2019-12-16
282
    $loop++;
283

            
284
    my $notifications = $hlink->check_notifications();
285
    if ($notifications->{code}) {
286
        log_bot('check_notifications: ' . HiPi::Huawei::Errors->get_error_message($notifications->{code}));
simplification table + répon...
admin cloud-section (root) authored on 2019-03-17
287
    }
changement de moyen de commu...
seb authored on 2019-12-16
288
#TODO    elsif ($notifications->{OnlineUpdateStatus} != 10) {
289
#TODO        trouver les significations
290
#TODO    }
291
    elsif ($notifications->{UnreadMessage}) {
292
        my $inbox = $hlink->get_inbox();
293
        if ($inbox->{code}) {
294
            log_bot('get_inbox: ' . HiPi::Huawei::Errors->get_error_message($inbox->{code}));
295
        }
296
        elsif (defined $inbox->{Count} and $inbox->{Count} > 0) {
297
#            log_bot($inbox->{Count} . " messages dans inbox");
298
            for (my $i = 0; $i < $inbox->{Count}; $i++) {
299
#                log_bot("id " . $inbox->{Messages}[$i]->{Index} . ", status: " . $inbox->{Messages}[$i]->{Smstat});
300
                if ($inbox->{Messages}[$i]->{Smstat}) { # message lu
301
                    my $delete = $hlink->delete_sms($inbox->{Messages}[$i]->{Index});
302
                    if ($delete->{code}) {
303
                        log_bot('delete_sms: ' . HiPi::Huawei::Errors->get_error_message($delete->{code}));
304
                    }
305
#                    log_bot("id " . $inbox->{Messages}[$i]->{Index} . " deleted");
306
                }
307
                else {
308
                    $inbox_sms_queue->enqueue($inbox->{Messages}[$i]);
309
#                    log_bot("id " . $inbox->{Messages}[$i]->{Index} . " enqueued");
310
                    my $read = $hlink->set_sms_read($inbox->{Messages}[$i]->{Index});
311
                    if ($read->{code}) {
312
                        log_bot('set_sms_read: ' . HiPi::Huawei::Errors->get_error_message($read->{code}));
313
                    }
314
#                    log_bot("id " . $inbox->{Messages}[$i]->{Index} . " marked as read") if defined $inbox->{Messages}[$i]->{Index};
315
                }
316
            }
317
        }
318
    }
319

            
320
#on vérifie toutes les 30 secondes
321
    sleep 30;
322
    log_bot('outbox_sms not running') unless ($outbox_sms->is_running());
323
    next if ($loop % 20);
324
    $loop = 0;
325

            
326
# nettoyage des envoyés toutes les 10 minutes
327
    my $outbox = $hlink->get_outbox();
328
    if ($outbox->{code}) {
329
        log_bot('get_outbox: ' . HiPi::Huawei::Errors->get_error_message($outbox->{code}));
330
    }
331
    elsif (defined $outbox->{Count} and $outbox->{Count} > 1) {
332
#        log_bot($outbox->{Count} . " messages dans outbox");
333
# on conserve le dernier envoyé
334
        for (my $i = 1; $i < $outbox->{Count}; $i++) {
335
            my $delete = $hlink->delete_sms($outbox->{Messages}[$i]->{Index});
336
            if ($delete->{code}) {
337
                log_bot('delete_sms: ' . HiPi::Huawei::Errors->get_error_message($delete->{code}));
338
            }
339
#            log_bot("id " . $outbox->{Messages}[$i]->{Index} . " deleted");
340
        }
simplification table + répon...
admin cloud-section (root) authored on 2019-03-17
341
    }
initial commit
admin cloud-section (root) authored on 2016-12-10
342
}