apps / sms / bot /
Newer Older
352 lines | 12.417kb
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;
144

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

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

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

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

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

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

            
initial commit
admin cloud-section (root) authored on 2016-12-10
222
        my %part_from_user = (
passage des regex dans le fi...
admin cloud-section (root) authored on 2017-02-17
223
            $cfg::user{"message de groupe"} => sub {
changement de moyen de commu...
seb authored on 2019-12-16
224
                $msg->{groupe} = lc $1;
225
                if (authorized_on_table(groupe => $msg->{groupe}, id => $msg->{Phone})) {
226
                    &massive_send_sms(\%$msg);
simplification table + répon...
admin cloud-section (root) authored on 2019-03-17
227
                }
initial commit
admin cloud-section (root) authored on 2016-12-10
228
            },
passage des regex dans le fi...
admin cloud-section (root) authored on 2017-02-17
229
            $cfg::user{"message pour un destinataire"} => sub {
changement de moyen de commu...
seb authored on 2019-12-16
230
                $outbox_sms_queue->enqueue([$1, $msg->{Content}]);
initial commit
admin cloud-section (root) authored on 2016-12-10
231
            },
supervision du service de SM...
Sébastien authored on 2022-06-03
232
            $cfg::user{"supervision"} => sub {
233
                if ($1 eq 'réception') {
234
                    $outbox_sms_queue->insert(0, [$msg->{Phone}, "supervision envoi"]);
235
                    open my $fh, '>', '/dev/shm/smsbot.reception.ok';
236
                    close $fh;
237
                }
238
                elsif ($1 eq 'envoi') {
239
                    open my $fh, '>', '/dev/shm/smsbot.envoi.ok';
240
                    close $fh;
241
                }
242
            },
passage des regex dans le fi...
admin cloud-section (root) authored on 2017-02-17
243
            $cfg::user{"ping"} => sub {
changement de moyen de commu...
seb authored on 2019-12-16
244
                my $envoi_en_cours = '';
245
                if ($outbox_sms_queue->pending() > 0) {
fix problème avec dequeue co...
Sébastien authored on 2019-12-22
246
#                    for (my $queue_id = $outbox_sms_queue->pending(); $queue_id >= 0; $queue_id--) {
247
#                        log_bot(Dumper($outbox_sms_queue->peek($queue_id)));
248
#                    }
changement de moyen de commu...
seb authored on 2019-12-16
249
                    $envoi_en_cours = "\nenvoi en cours de traitement (reste " . $outbox_sms_queue->pending() . ") ";
250
                    $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
251
                }
changement de moyen de commu...
seb authored on 2019-12-16
252
                log_bot("envoi d'un pong à $msg->{Phone} $msg->{PhoneOwner} $envoi_en_cours");
253
                $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
254
            },
initial commit
admin cloud-section (root) authored on 2016-12-10
255
        );
256

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

            
260
        my @results = sql_request("SELECT * FROM " . $cfg::config{table} . " WHERE phone = '$msg->{Phone}'");
261
        my $number_of_candidates = @results;
262
        $number_of_candidates == 0 and return;
263
        $msg->{PhoneOwner} = '(';
264
        foreach (@results) {
265
            $msg->{PhoneOwner} .= "$_->{firstname} $_->{lastname}";
266
            --$number_of_candidates > 0 and $msg->{PhoneOwner} .= ' ou ';
267
            $msg->{Email} = $_->{email};
initial commit
admin cloud-section (root) authored on 2016-12-10
268
        }
changement de moyen de commu...
seb authored on 2019-12-16
269
        $msg->{PhoneOwner} .= ')';
270
        $msg->{Subject} = "SMS recu de $msg->{Phone} $msg->{PhoneOwner}";
271

            
272
        if (defined $msg->{Phone} and !(is_authorized(\%$msg) and react_on_message(\%part_from_user, \%$msg))) {
273
            log_bot("message de $msg->{Phone} $msg->{PhoneOwner}");
274
            $mail_queue->enqueue(\%$msg);
initial commit
admin cloud-section (root) authored on 2016-12-10
275
        }
276

            
changement de moyen de commu...
seb authored on 2019-12-16
277
        undef $msg;
initial commit
admin cloud-section (root) authored on 2016-12-10
278
    }
279
}
280

            
changement de moyen de commu...
seb authored on 2019-12-16
281
$inbox_sms->detach;    # gère la file des événements produits par GTalkSMS
282
log_bot("inbox thread ok");
283
$outbox_sms->detach;   # gère la file des envois de SMS par GTalkSMS
284
log_bot("outbox thread ok");
285
$mail->detach;         # gère la file des mails
286
log_bot("mail thread ok");
initial commit
admin cloud-section (root) authored on 2016-12-10
287

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

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

            
294
    my $notifications = $hlink->check_notifications();
295
    if ($notifications->{code}) {
296
        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
297
    }
changement de moyen de commu...
seb authored on 2019-12-16
298
#TODO    elsif ($notifications->{OnlineUpdateStatus} != 10) {
299
#TODO        trouver les significations
300
#TODO    }
301
    elsif ($notifications->{UnreadMessage}) {
302
        my $inbox = $hlink->get_inbox();
303
        if ($inbox->{code}) {
304
            log_bot('get_inbox: ' . HiPi::Huawei::Errors->get_error_message($inbox->{code}));
305
        }
306
        elsif (defined $inbox->{Count} and $inbox->{Count} > 0) {
307
#            log_bot($inbox->{Count} . " messages dans inbox");
308
            for (my $i = 0; $i < $inbox->{Count}; $i++) {
309
#                log_bot("id " . $inbox->{Messages}[$i]->{Index} . ", status: " . $inbox->{Messages}[$i]->{Smstat});
310
                if ($inbox->{Messages}[$i]->{Smstat}) { # message lu
311
                    my $delete = $hlink->delete_sms($inbox->{Messages}[$i]->{Index});
312
                    if ($delete->{code}) {
313
                        log_bot('delete_sms: ' . HiPi::Huawei::Errors->get_error_message($delete->{code}));
314
                    }
315
#                    log_bot("id " . $inbox->{Messages}[$i]->{Index} . " deleted");
316
                }
317
                else {
318
                    $inbox_sms_queue->enqueue($inbox->{Messages}[$i]);
319
#                    log_bot("id " . $inbox->{Messages}[$i]->{Index} . " enqueued");
320
                    my $read = $hlink->set_sms_read($inbox->{Messages}[$i]->{Index});
321
                    if ($read->{code}) {
322
                        log_bot('set_sms_read: ' . HiPi::Huawei::Errors->get_error_message($read->{code}));
323
                    }
324
#                    log_bot("id " . $inbox->{Messages}[$i]->{Index} . " marked as read") if defined $inbox->{Messages}[$i]->{Index};
325
                }
326
            }
327
        }
328
    }
329

            
330
#on vérifie toutes les 30 secondes
331
    sleep 30;
332
    log_bot('outbox_sms not running') unless ($outbox_sms->is_running());
333
    next if ($loop % 20);
334
    $loop = 0;
335

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