File size: 41,784 Bytes
020c337
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
#!/usr/bin/python
#coding: utf-8
# +-------------------------------------------------------------------
# | aaPanel
# +-------------------------------------------------------------------
# | Copyright (c) 2015-2099 aaPanel(www.aapanel.com) All rights reserved.
# +-------------------------------------------------------------------
# | Author: wzjie <wzj@aapanel.com>
# | Author: zhwen <zhw@aapanel.com>
# +-------------------------------------------------------------------

# +--------------------------------------------------------------------
# |   宝塔邮局
# +--------------------------------------------------------------------
import sys,re,os,json
sys.path.append("class/")
sys.path.append("/www/server/panel/class/")
import public
main_cf = "/etc/postfix/main.cf"
download_url = public.get_url()


def get_postconf():
    if os.path.exists("/usr/sbin/postconf"):
        return "/usr/sbin/postconf"
    elif os.path.exists("/sbin/postconf"):
        return "/sbin/postconf"
    else:
        return "postconf"

class change_to_rspamd:

    def change_dkim_server(self):
        # 更换dkim服务器,从opendkim切换到rspamd
        pass

    def change_postfix_conf(self):
        # postfix配置修改为支持rspamd
        shell = """
    {postconf} -e "myhostname = $(hostname)"
    {postconf} -e "smtpd_milters = inet:127.0.0.1:11332"
    {postconf} -e "non_smtpd_milters = inet:127.0.0.1:11332"
    {postconf} -e "milter_mail_macros = i {{mail_addr}} {{client_addr}} {{client_name}} {{auth_authen}}"
    {postconf} -e "milter_protocol = 6"
    {postconf} -e "milter_default_action = accept"
    """.format(postconf=get_postconf())
        public.ExecShell(shell)

    def comment_old_spam(self):
        conf = public.readFile(main_cf)
        if not conf:
            return
        rep = "##BT-ANTISPAM-BEGIN(.|\n)+##BT-ANTISPAM-END"
        conf = re.sub(rep, "", conf)
        public.writeFile(main_cf, conf)

    def change_dovecot_conf(self):
        # dovecot配置修改为支持rspamd
        shell = """
    wget "{download_conf_url}/mail_sys/dovecot/90-sieve_rspamd.conf" -O /etc/dovecot/conf.d/90-sieve.conf -T 10
    wget "{download_conf_url}/mail_sys/dovecot/20-lmtp.conf" -O /etc/dovecot/conf.d/20-lmtp.conf -T 10
    wget "{download_conf_url}/mail_sys/dovecot/20-imap.conf" -O /etc/dovecot/conf.d/20-imap.conf -T 10
    wget "{download_conf_url}/mail_sys/dovecot/15-mailboxes.conf" -O /etc/dovecot/conf.d/15-mailboxes.conf -T 10
    """.format(download_conf_url=download_url)
        public.ExecShell(shell)

    def main(self):
        self.comment_old_spam()
        self.change_postfix_conf()
        self.change_dovecot_conf()
        mail_server_init().setup_rspamd()

class mail_server_init:

    def __init__(self):
        self.sys_v = public.get_linux_distribution().lower()
        self.logfile = '/tmp/mail_init.log'
        self.db_files = {
            'postfixadmin': '/www/vmail/postfixadmin.db',
            'postfixmaillog': '/www/vmail/postfixmaillog.db',
            'mail_unsubscribe': '/www/vmail/mail_unsubscribe.db',
            'abnormal_recipient': '/www/vmail/abnormal_recipient.db'
        }
    def write_logs(self,content,emtpy=None):
        if emtpy:
            public.writeFile(self.logfile, '')
        if '\n' not in content:
            content += '\n'
        public.writeFile(self.logfile,content,'a+')

    def check_env(self):
        data = {}
        data['HostName'] = self.check_hostname()
        data['Postfix-install'] = {"status":True,"msg":"Postfix已经安装"} if os.path.exists('/usr/sbin/postfix') else {"status":False,"msg":"Postfix未安装,请点击修复按钮"}
        data['Dovecot-install'] = {"status":True,"msg":"Deovecot已经安装"} if os.path.exists('/usr/sbin/dovecot') else {"status":False,"msg":"Dovecot未安装,请点击修复按钮"}
        data['Postfix-Version'] = self.check_postfix_ver()
        data['Redis-install'] = {"status":True,"msg":"Redis已经安装"} if os.path.exists('/www/server/redis/src/redis-server') else {"status":False,"msg":"请到软件商店内安装Redis"}
        data['Redis-Passwd'] = self.check_redis_passwd(data['Redis-install'])
        data['Rspamd-install'] = {"status":True,"msg":"Rspamd已经安装"} if os.path.exists('/usr/bin/rspamd') else {"status":False,"msg":"Rspamd未安装,请点击修复按钮"}
        data['Sqlite-support'] = self.check_sqlite()
        data['SElinux'] ={"status":True,"msg":"SElinux已经禁用"} if not 'enforcing' in public.ExecShell('getenforce')[0].lower() else {"status":False,"msg":"请先禁用SElinux"}
        return data

    # 安装并配置postfix, dovecot
    def setup_mail_sys(self, args):
        '''
        安装邮局系统主函数
        :param args:
        :return:
        '''
        self.write_logs('|-Set up the postfix service to listen to all network cards...')
        public.ExecShell('{postconf} -e "inet_interfaces = all"'.format(postconf=get_postconf()))
        self.write_logs('|-Checking system key directory permissions...')
        if self._check_syssafe():
            self.write_logs('|-Check system key directory permissions: failed')
            return public.returnMsg(False, '请先关闭【系统加固】')
        self.write_logs('|-Initializing...')
        if not self.prepare_work():
            return public.returnMsg(False, '初始化失败')
        if not self.conf_postfix()['status']:
            return public.returnMsg(False, 'Postfix配置失败!')
        if not self.conf_dovecot():
            return public.returnMsg(False, 'Dovecot配置失败!')
        if not self.setup_rspamd():
            return public.returnMsg(False, 'Rspamd配置失败!')
        # if not self.setup_opendkim():
        #     return public.returnMsg(False, 'Failed to configure opendkim 0')

        # 初始化dns数据库
        from sslModel import dataModel
        dataModel.main().check_table()

        self.write_logs('|{}'.format("-"*60))
        self.write_logs('|-Initialized successfully!')
        return public.returnMsg(True, '初始化完成')

    # 检查系统加固是否开启
    def _check_syssafe(self, args=None):
        if not os.path.exists('/www/server/panel/plugin/syssafe/'):
            return False
        data = json.loads(public.readFile('/www/server/panel/plugin/syssafe/config.json'))
        return data['open']

    def check_hostname(self):
        import socket
        rep = '^(?!:\/\/)(?=.{1,255}$)((.{1,63}\.){1,127}(?![0-9]*$)[a-z0-9-]+\.?)$'
        hostname = socket.gethostname()
        if re.search(rep,hostname):
            return public.returnMsg(True,'success')
        return public.returnMsg(False, '你的主机名 ({}) 不合规定, 需要是完整域名'
                                       '你可以通过以下命令修复你的主机名 '
                                       '在ssh终端执行 \'hostnamectl set-hostname --static mail.example.com\''.format(hostname))

    def M(self, table_name):
        import db
        sql = db.Sql()
        sql._Sql__DB_FILE = '/www/vmail/postfixadmin.db'
        return sql.table(table_name)
    def MD(self, table_name, db_key):
        if db_key not in self.db_files:
            raise ValueError(f"Unknown database key: {db_key}")
        import db
        sql = db.Sql()
        sql._Sql__DB_FILE = self.db_files[db_key]
        sql._Sql__encrypt_keys = []
        return sql.table(table_name)

    # 放行端口
    def _release_port(self, port):
        from collections import namedtuple
        try:
            import firewalls
            get = namedtuple("get", ["port", "ps", "type"])
            get.port = port
            get.ps = 'Mail-Server'
            get.type = "port"
            firewalls.firewalls().AddAcceptPort(get)
            # return get.port
            return port
        except Exception as e:
            return "Release failed {}".format(e)

    def prepare_work(self):
        '''
        安装前的准备工作
        :return:
        '''
        shell_str = '''
useradd -r -u 150 -g mail -d /www/vmail -s /sbin/nologin -c "Virtual Mail User" vmail
mkdir -p /www/vmail
chmod -R 770 /www/vmail
chown -R vmail:mail /www/vmail

if [ ! -f "/www/vmail/postfixadmin.db" ]; then
    touch /www/vmail/postfixadmin.db
    chown vmail:mail /www/vmail/postfixadmin.db
    chmod 660 /www/vmail/postfixadmin.db
fi'''
        self.write_logs('',emtpy=True)
        self.write_logs('|-Adding user: vmail')
        self.write_logs('|-Create mail storage directory: /www/vmail')
        self.write_logs('|-Set directory permissions: 770')
        self.write_logs('|-Set directory owner: vmail:mail')
        if "centos" in self.sys_v:
            public.ExecShell(shell_str)
        elif "ubuntu" in self.sys_v:
            public.ExecShell(shell_str)
            # copy证书
            if not os.path.exists("/etc/pki/dovecot/certs/dovecot.pem"):
                self.write_logs('|-Generate dovecot certificate: /etc/pki/dovecot/certs/dovecot.pem')
                shell_str = """
                sudo mkdir -p /etc/pki/dovecot/certs/
                sudo mkdir -p /etc/pki/dovecot/private/
                sudo cp /etc/ssl/certs/ssl-cert-snakeoil.pem /etc/pki/dovecot/certs/dovecot.pem
                sudo mv /etc/ssl/private/ssl-cert-snakeoil.key /etc/pki/dovecot/private/dovecot.pem
                """
                public.ExecShell(shell_str)
        else:
            return public.returnMsg(False, "目前仅支持Centos和Ubuntu")
        # 配置防火墙
        for i in ["25", "110", "143", "465", "995", "993", "587"]:
            self.write_logs('|-Releasing port: {}'.format(i))
            self._release_port(i)
            # 调用防火墙开放端口
            from safeModel.firewallModel import main as firewall
            firewall_obj = firewall()
            # protocol port type address brief
            new_get = public.dict_obj()
            new_get.protocol = "tcp"
            new_get.ports = str(i)
            new_get.choose = "all"
            new_get.address = ""
            new_get.domain = ""
            new_get.types = "accept"
            new_get.brief = "Mail-Server"
            new_get.source = ""
            firewall_obj.create_rules(new_get)
        # 创建数据表
        # 域名表 增字段 邮箱数量 mailboxes 邮箱默认大小 mailbox_quota  域名配额 quota    每秒几个邮件 rate_limit
        self.write_logs('|-Initializing database...')
        sql = '''CREATE TABLE IF NOT EXISTS `domain` (
          `domain` varchar(255) NOT NULL,
          `a_record` TEXT DEFAULT "",
          `mailboxes` int DEFAULT 50,                       -- 创建邮箱数量
          `mailbox_quota` bigint(20) NOT NULL DEFAULT 5368709120,    -- 邮箱默认空间大小
          `quota` bigint(20) NOT NULL DEFAULT 10737418240,            -- 域名配额
          `rate_limit` int DEFAULT 12,                       -- 每秒几个邮件
          `created` datetime NOT NULL,
          `active` tinyint(1) NOT NULL DEFAULT 1,
          PRIMARY KEY (`domain`));'''

        with self.M("") as obj:
            obj.execute(sql, ())

        # self.M('').execute(sql, ())


        # 邮箱账号 增加massage 记录发件数
        sql = '''CREATE TABLE IF NOT EXISTS `mailbox` (
          `username` varchar(255) NOT NULL,
          `password` varchar(255) NOT NULL,
          `password_encode` varchar(255) NOT NULL,
          `full_name` varchar(255) NOT NULL,
          `is_admin` tinyint(1) NOT NULL DEFAULT 0,
          `maildir` varchar(255) NOT NULL,
          `quota` bigint(20) NOT NULL DEFAULT 0,
          `local_part` varchar(255) NOT NULL,
          `domain` varchar(255) NOT NULL,
          `created` datetime NOT NULL,
          `modified` datetime NOT NULL,
          `active` tinyint(1) NOT NULL DEFAULT 1,
          PRIMARY KEY (`username`));'''
        with self.M("") as obj:
            obj.execute(sql, ())
        # self.M('').execute(sql, ())

        # 邮件转发
        sql = '''CREATE TABLE IF NOT EXISTS `alias` (
          `address` varchar(255) NOT NULL,
          `goto` text NOT NULL,
          `domain` varchar(255) NOT NULL,
          `created` datetime NOT NULL,
          `modified` datetime NOT NULL,
          `active` tinyint(1) NOT NULL DEFAULT 1,
          PRIMARY KEY (`address`));'''
        with self.M("") as obj:
            obj.execute(sql, ())
        # self.M('').execute(sql, ())
        # 系统内用表 没看到使用
        sql = '''CREATE TABLE IF NOT EXISTS `alias_domain` (
          `alias_domain` varchar(255) NOT NULL, 
          `target_domain` varchar(255) NOT NULL,
          `created` datetime NOT NULL,
          `modified` datetime NOT NULL,
          `active` tinyint(1) NOT NULL DEFAULT 1,
          PRIMARY KEY (`alias_domain`));'''
        with self.M("") as obj:
            obj.execute(sql, ())
        # self.M('').execute(sql, ())
        # 新增3个表  批量发件用
        # 邮件模版表
        sql = '''CREATE TABLE IF NOT EXISTS `temp_email` (
          `id` INTEGER  PRIMARY KEY AUTOINCREMENT,        
          `name` varchar(255) NULL,         -- 邮件名 有模版时为模版名
          `type` tinyint(1) NOT NULL DEFAULT 0,  --上传html 0   拖拽html 1
          `content` text NOT NULL,          -- 邮件正文 路径
          `render` text NOT NULL,   -- html渲染数据
          `created` INTEGER NOT NULL,  
          `modified` INTEGER NOT NULL,
          `is_temp` tinyint(1) NOT NULL DEFAULT 0  -- 是否是模版
          );'''
        with self.M("") as obj:
            obj.execute(sql, ())
        # self.M('').execute(sql, ())

        # 任务表
        sql = '''CREATE TABLE IF NOT EXISTS `email_task` (
          `id` INTEGER  PRIMARY KEY AUTOINCREMENT,    
          `task_name` varchar(255) NOT NULL,        -- 任务名
          `addresser` varchar(320) NOT NULL,        -- 发件人
          `recipient_count` int NOT NULL,           -- 收件人数量
          `task_process` tinyint NOT NULL,     -- 任务进程  0待执行   1执行中  2 已完成
          `pause` tinyint NOT NULL,      -- 暂停状态  1 暂停中     0 未暂停     执行中的任务才能暂停
          `temp_id` INTEGER NOT NULL,          -- 邮件对应id
          `is_record` INTEGER NOT NULL DEFAULT 0,          -- 是否记录到发件箱
          `unsubscribe` INTEGER NOT NULL DEFAULT 0,      -- 是否增加退订按钮   0 没有   1 增加退订按钮
          `threads` INTEGER NOT NULL DEFAULT 0,          -- 线程数量 控制发送线程数 0时自动控制线程   0~10
          `created` INTEGER NOT NULL,
          `modified` INTEGER NOT NULL,
          `remark` text,           -- 备注
          `etypes` varchar(320) NOT NULL DEFAULT '1',         -- 邮件类型id 默认为1  多类型 1,2,3
          `start_time` INTEGER NOT NULL DEFAULT 0,            -- 任务开始时间
          `subject` text NULL,          -- 邮件主题   改task存  可空
          `full_name` varchar(255),  -- 新发件人名    改task存  可空
          `recipient` text NOT NULL,        -- 收件人路径 改task存
          `track_open` INTEGER NOT NULL DEFAULT 0,    --  追踪邮件打开
          `track_click` INTEGER NOT NULL DEFAULT 0,    --  链接点击
          `active` tinyint(1) NOT NULL DEFAULT 0    --  预留字段
          );'''
        with self.M("") as obj:
            obj.execute(sql, ())
        # self.M('').execute(sql, ())

        # 发送统计表 改 错误详情表  task_id与recipient 联合唯一  避免重试邮件重复记录

        sql = '''CREATE TABLE IF NOT EXISTS `task_count` (
          `id` INTEGER  PRIMARY KEY AUTOINCREMENT,    
          `task_id` INTEGER NOT NULL,                   -- 所属任务编号
          `recipient` varchar(320) NOT NULL,            -- 收件人
          `delay` varchar(320) NOT NULL,            -- 延时
          `delays` varchar(320) NOT NULL,            -- 各阶段延时
          `dsn` varchar(320) NOT NULL,            -- dsn
          `relay` text NOT NULL,            -- 中继服务器
          `domain` varchar(320) NOT NULL,               -- 域名
          `status` varchar(255) NOT NULL,               -- 错误状态
          `err_info` text NOT NULL,                      -- 错误详情
          `created` INTEGER NOT NULL DEFAULT 0,
           UNIQUE (`task_id`, `recipient`)  -- 联合唯一约束
          );'''
        with self.M("") as obj:
            obj.execute(sql, ())

        # 邮件类型表  欢迎邮件 营销邮件
        sql = '''CREATE TABLE IF NOT EXISTS `mail_type` (
          `id` INTEGER  PRIMARY KEY AUTOINCREMENT,
          `mail_type` varchar(320) NOT NULL,            -- 邮件类型
          `created` INTEGER NOT NULL,
          `active` tinyint(1) NOT NULL DEFAULT 0    --  预留字段
          );'''
        with self.M("") as obj:
            obj.execute(sql, ())

        # 插入一条类型
        sql_insert = ''' INSERT INTO `mail_type`(`mail_type`, `created`) VALUES ('Default',  strftime('%s', 'now'));'''
        with self.M("") as obj:
            obj.execute(sql_insert, ())

        # 退订表   退订时间和退订邮箱联合唯一   /www/vmail/mail_unsubscribe.db
        sql = '''CREATE TABLE IF NOT EXISTS `mail_unsubscribe` (
           `id` INTEGER  PRIMARY KEY AUTOINCREMENT,
           `created` INTEGER NOT NULL,
           `recipient` varchar(320) NOT NULL,            -- 收件人
           `etype`  INTEGER NOT NULL DEFAULT 1,           -- 邮件类型id
           `active` tinyint(1) NOT NULL DEFAULT 0,    --  0 取消订阅      1订阅
           `task_id` INTEGER  DEFAULT 0,       -- 群发任务 id  (退订有关联id  订阅没有)
           UNIQUE(etype, recipient)
           );'''

        with self.MD("", "mail_unsubscribe") as obj3:
            aa = obj3.execute(sql, ())
            # public.print_log("更新退订表 mail_unsubscribe --{}".format(aa))


        # 统计日志 收件人和日志时间联合唯一
        sql = '''CREATE TABLE IF NOT EXISTS `mail_errlog` (
          `id` INTEGER  PRIMARY KEY AUTOINCREMENT,
          `created` INTEGER NOT NULL,
          `recipient` varchar(320) NOT NULL,            -- 收件人
          `delay` varchar(320) NOT NULL,            -- 延时
          `delays` varchar(320) NOT NULL,            -- 各阶段延时
          `dsn` varchar(320) NOT NULL,            -- dsn
          `relay` text NOT NULL,                    -- 中继服务器
          `domain` varchar(320) NOT NULL,               -- 域名
          `status` varchar(255) NOT NULL,               -- 错误状态
          `err_info` text NOT NULL,                   -- 错误详情
          UNIQUE(created, recipient)
          );'''
        with self.MD("", "postfixmaillog") as obj2:
            obj2.execute(sql, ())
        # self.M2('').execute(sql, ())



        # 邮件日志分析统计表  接收 received, 发送 delivered, 转发 forwarded, 延迟 deferred, 退回 bounced, 拒绝 rejected
        sql = '''CREATE TABLE IF NOT EXISTS `log_analysis` (
          `id` INTEGER  PRIMARY KEY AUTOINCREMENT,
          `received` INTEGER NOT NULL DEFAULT 0,        -- 接收
          `delivered` INTEGER NOT NULL DEFAULT 0,       -- 发送
          `forwarded` INTEGER NOT NULL DEFAULT 0,       -- 转发
          `deferred` INTEGER NOT NULL DEFAULT 0,        -- 延迟
          `bounced` INTEGER NOT NULL DEFAULT 0,         -- 退回
          `rejected` INTEGER NOT NULL DEFAULT 0,        -- 拒绝
          `time` INTEGER NOT NULL,                    -- 时间  每小时时间戳
           UNIQUE(`created`)    
          );'''
        with self.M("") as obj:
            obj.execute(sql, ())

        # 异常用户表
        sql = '''CREATE TABLE IF NOT EXISTS `abnormal_recipient` (
        `id` INTEGER  PRIMARY KEY AUTOINCREMENT,
        `created` INTEGER NOT NULL,               -- 邮件时间 时间戳
        `recipient` varchar(320) NOT NULL,        -- 收件人
        `count` INTEGER NOT NULL,                 -- 次数
        `status` varchar(255) NOT NULL,           -- 状态
        `task_name` varchar(255) NOT NULL,      -- 任务名
        UNIQUE(recipient)
        );'''

        with self.MD("", "abnormal_recipient") as obj4:
            obj4.execute(sql, ())

        # # 邮件日志分析统计表
        # sql = '''CREATE TABLE IF NOT EXISTS `email_log` (
        #   --`id` INTEGER  PRIMARY KEY AUTOINCREMENT,
        #   `hostname` varchar(320) NOT NULL,            -- 主机名 hello-mail
        #   `process` varchar(320) NOT NULL,            -- 进程 postfix/smtp[3033510]
        #   `email_id` varchar(320) NOT NULL,            -- 邮件id  17C2A38062F
        #   `recipient` varchar(320) NOT NULL,            -- 收件人
        #   `relay` text NOT NULL,            -- 中继服务器
        #   `delay` varchar(320) NOT NULL,            -- 延时
        #   `delays` varchar(320) NOT NULL,            -- 各阶段延时  连接建立,发送数据,等待响应,传输完成
        #   `dsn` varchar(320) NOT NULL,            -- dsn
        #   `status` varchar(255) NOT NULL,               -- 错误状态
        #   `domain` varchar(320) NOT NULL,               -- 域名
        #   `err_info` text NOT NULL,                      -- 错误详情
        #   `created` INTEGER NOT NULL,                   -- 时间戳
        #    PRIMARY KEY (`email_id`));
        #   '''
        # self.M('').execute(sql, ())

        # 判断/www/vmail/postfixadmin.db文件是否存在
        if os.path.exists('/www/vmail/postfixadmin.db'):
            self.write_logs('|-The database is initialized successfully...')
            return True
        else:
            self.write_logs('|-Database initialization failed...')
            return False

    def _check_sendmail(self):
        pid = '/run/sendmail/mta/sendmail.pid'
        if os.path.exists(pid):
            self.write_logs('|-Check that there is an additional mail service aaa, which is stopping')
            public.ExecShell('systemctl stop sendmail && systemctl disable sendmail')

    def conf_postfix(self):
        '''
        安装,配置postfix服务, postfix提供发信功能
        :return:
        '''
        # 检查sendmail服务,如果有则停止
        self._check_sendmail()
        # 修改postfix配置
        self.write_logs('|-Initializing postfix...')
        edit_postfix_conf_shell = '''
{postconf} -e "myhostname = $(hostname)"
{postconf} -e "inet_interfaces = all"
{postconf} -e "mydestination ="

{postconf} -e "virtual_mailbox_domains = sqlite:/etc/postfix/sqlite_virtual_domains_maps.cf"
{postconf} -e "virtual_alias_maps = sqlite:/etc/postfix/sqlite_virtual_alias_new_maps.cf, sqlite:/etc/postfix/sqlite_virtual_alias_domain_new_maps.cf, sqlite:/etc/postfix/sqlite_virtual_alias_domain_catchall_new_maps.cf, sqlite:/etc/postfix/bt_catchnone_maps.cf"
{postconf} -e "virtual_mailbox_maps = sqlite:/etc/postfix/sqlite_virtual_mailbox_maps.cf, sqlite:/etc/postfix/sqlite_virtual_alias_domain_mailbox_maps.cf"

{postconf} -e "smtpd_sasl_type = dovecot"
{postconf} -e "smtpd_sasl_path = private/auth"
{postconf} -e "smtpd_sasl_auth_enable = yes"
{postconf} -e "smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination"

{postconf} -e "smtpd_use_tls = yes"
{postconf} -e "smtp_tls_security_level = may"
{postconf} -e "smtpd_tls_security_level = may"

{postconf} -e "virtual_transport = lmtp:unix:private/dovecot-lmtp"
{postconf} -e "smtpd_milters = inet:127.0.0.1:11332"
{postconf} -e "non_smtpd_milters = inet:127.0.0.1:11332"
{postconf} -e "milter_mail_macros = i {{mail_addr}} {{client_addr}} {{client_name}} {{auth_authen}}"
{postconf} -e "milter_protocol = 6"
{postconf} -e "milter_default_action = accept"
{postconf} -e "message_size_limit = 102400000"
'''.format(postconf=get_postconf())
        public.ExecShell(edit_postfix_conf_shell)
        self.write_logs('|-Downloading additional configuration files...')
        download_sql_conf_shell = '''
wget "{download_conf_url}/mail_sys/postfix/master.cf" -O /etc/postfix/master.cf -T 10 >> {logfile} 2>&1
wget "{download_conf_url}/mail_sys/postfix/sqlite_virtual_alias_domain_catchall_new_maps.cf" -O /etc/postfix/sqlite_virtual_alias_domain_catchall_new_maps.cf -T 10 >> {logfile} 2>&1
wget "{download_conf_url}/mail_sys/postfix/bt_catchnone_maps.cf" -O /etc/postfix/bt_catchnone_maps.cf -T 10 >> {logfile} 2>&1
wget "{download_conf_url}/mail_sys/postfix/sqlite_virtual_alias_domain_new_maps.cf" -O /etc/postfix/sqlite_virtual_alias_domain_new_maps.cf -T 10 >> {logfile} 2>&1
wget "{download_conf_url}/mail_sys/postfix/sqlite_virtual_alias_domain_mailbox_maps.cf" -O /etc/postfix/sqlite_virtual_alias_domain_mailbox_maps.cf -T 10 >> {logfile} 2>&1
wget "{download_conf_url}/mail_sys/postfix/sqlite_virtual_alias_domain_maps.cf" -O /etc/postfix/sqlite_virtual_alias_domain_maps.cf -T 10 >> {logfile} 2>&1
wget "{download_conf_url}/mail_sys/postfix/sqlite_virtual_domains_maps.cf" -O /etc/postfix/sqlite_virtual_domains_maps.cf -T 10 >> {logfile} 2>&1
wget "{download_conf_url}/mail_sys/postfix/sqlite_virtual_alias_new_maps.cf" -O /etc/postfix/sqlite_virtual_alias_new_maps.cf -T 10 >> {logfile} 2>&1
wget "{download_conf_url}/mail_sys/postfix/sqlite_virtual_domains_new_maps.cf" -O /etc/postfix/sqlite_virtual_domains_new_maps.cf -T 10 >> {logfile} 2>&1
wget "{download_conf_url}/mail_sys/postfix/sqlite_virtual_mailbox_maps.cf" -O /etc/postfix/sqlite_virtual_mailbox_maps.cf -T 10 >> {logfile} 2>&1
wget "{download_conf_url}/mail_sys/postfix/btrule.cf" -O /etc/postfix/btrule.cf -T 10 >> {logfile} 2>&1
'''.format(download_conf_url=download_url,logfile=self.logfile)
        aaa = public.ExecShell(download_sql_conf_shell)
        # public.print_log("执行命令后返回 --{}".format(aaa))

        result = public.readFile("/etc/postfix/sqlite_virtual_mailbox_maps.cf")
        if not result or not re.search(r"\n*query\s*=\s*", result):
            self.write_logs('|- Read file content {}: Failed'.format("/etc/postfix/sqlite_virtual_mailbox_maps.cf"))
            return public.returnMsg(False,"获取邮局配置失败!")

        restart_service_shell = 'systemctl enable postfix && systemctl restart postfix'
        self.write_logs('|-Restarting postfix service...')
        public.ExecShell(restart_service_shell)
        return public.returnMsg(True,"配置成功!")

    def conf_dovecot(self):
        '''
        安装,配置dovecot服务, dovecot提供收信功能
        :return:
        '''
        self.write_logs('|-Initializing dovecot...')
        self.write_logs('|-Downloading additional configuration files...')
        download_conf_shell = '''
wget "{download_conf_url}/mail_sys/dovecot/dovecot-sql.conf.ext" -O /etc/dovecot/dovecot-sql.conf.ext -T 10 >> {logfile} 2>&1
wget "{download_conf_url}/mail_sys/dovecot/dovecot.conf" -O /etc/dovecot/dovecot.conf -T 10 >> {logfile} 2>&1
wget "{download_conf_url}/mail_sys/dovecot/10-mail.conf" -O /etc/dovecot/conf.d/10-mail.conf -T 10 >> {logfile} 2>&1
wget "{download_conf_url}/mail_sys/dovecot/10-ssl.conf" -O /etc/dovecot/conf.d/10-ssl.conf -T 10 >> {logfile} 2>&1
wget "{download_conf_url}/mail_sys/dovecot/10-master.conf" -O /etc/dovecot/conf.d/10-master.conf -T 10 >> {logfile} 2>&1
wget "{download_conf_url}/mail_sys/dovecot/10-auth.conf" -O /etc/dovecot/conf.d/10-auth.conf -T 10 >> {logfile} 2>&1

wget "{download_conf_url}/mail_sys/dovecot/90-sieve_rspamd.conf" -O /etc/dovecot/conf.d/90-sieve.conf -T 10 >> {logfile} 2>&1
wget "{download_conf_url}/mail_sys/dovecot/20-lmtp.conf" -O /etc/dovecot/conf.d/20-lmtp.conf -T 10 >> {logfile} 2>&1
wget "{download_conf_url}/mail_sys/dovecot/20-imap.conf" -O /etc/dovecot/conf.d/20-imap.conf -T 10 >> {logfile} 2>&1
wget "{download_conf_url}/mail_sys/dovecot/15-mailboxes.conf" -O /etc/dovecot/conf.d/15-mailboxes.conf -T 10 >> {logfile} 2>&1
'''.format(download_conf_url=download_url,logfile=self.logfile)
        public.ExecShell(download_conf_shell)
        result = public.readFile("/etc/dovecot/dovecot.conf")
        if not result or not re.search(r"\n*protocol\s+imap", result):
            self.write_logs('|-Read file content {}: Failed'.format("/etc/dovecot/dovecot.conf"))
            return False

        # 关闭protocols注释
        dovecot_conf = public.readFile("/etc/dovecot/dovecot.conf")
        dovecot_conf = re.sub(r"#protocols\s*=\s*imap\s*pop3\s*lmtp", "protocols = imap pop3 lmtp", dovecot_conf)
        public.writeFile("/etc/dovecot/dovecot.conf", dovecot_conf)

        if 'centos8' in self.sys_v:
            if not self.create_ssl():
                self.write_logs('|-Generate self-signed certificate: Failed')
                return False
        if not os.path.exists('/etc/pki/dovecot/private/dovecot.pem') or not os.path.exists(
                '/etc/pki/dovecot/certs/dovecot.pem'):
            self.create_ssl()
        restart_service_shell = '''
chown -R vmail:dovecot /etc/dovecot
chmod -R o-rwx /etc/dovecot

systemctl enable dovecot
systemctl restart  dovecot
'''
        self.write_logs('|-Restarting dovecot...')
        public.ExecShell(restart_service_shell)
        return True

    # 自签证书
    def create_ssl(self, get=None):
        import OpenSSL
        self.write_logs('|-生成自签证书...')
        from mailModel import mainModel as mail_sys_main
        mail_sys_main.main().back_file('/etc/pki/dovecot/certs/dovecot.pem')
        mail_sys_main.main().back_file('/etc/pki/dovecot/private/dovecot.pem')
        key = OpenSSL.crypto.PKey()
        key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
        cert = OpenSSL.crypto.X509()
        cert.set_serial_number(0)
        cert.get_subject().CN = public.GetLocalIp()
        cert.set_issuer(cert.get_subject())
        cert.gmtime_adj_notBefore(0)
        cert.gmtime_adj_notAfter(10 * 365 * 24 * 60 * 60)
        cert.set_pubkey(key)
        cert.sign(key, 'md5')
        cert_ca = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
        private_key = OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key)
        if not isinstance(cert_ca, str):
            cert_ca = cert_ca.decode()
        if not isinstance(private_key, str):
            private_key = private_key.decode()
        if len(cert_ca) > 100 and len(private_key) > 100:
            public.writeFile('/etc/pki/dovecot/certs/dovecot.pem', cert_ca)
            public.writeFile('/etc/pki/dovecot/private/dovecot.pem', private_key)
            return True
        else:
            mail_sys_main.main().restore_file('/etc/pki/dovecot/certs/dovecot.pem')
            mail_sys_main.main().restore_file('/etc/pki/dovecot/private/dovecot.pem')
            return False

    def check_postfix_ver(self):
        postfix_version = public.ExecShell(r"{postconf} mail_version|sed -r 's/.* ([0-9\.]+)$/\1/'".format(
            postconf=get_postconf()))[0].strip()
        if postfix_version.startswith('3'):
            return public.returnMsg(True,postfix_version)
        else:
            return public.returnMsg(False,"当前版本不支持或Postfix没有安装成功:{}".format(postfix_version))

    def check_redis_passwd(self,redis_install):
        redis_conf = public.readFile('/www/server/redis/redis.conf')
        if redis_install['status']:
            if re.search('\n\s*requirepass',redis_conf):
                return public.returnMsg(True,"Redis已经设置密码")
        return public.returnMsg(False,"请到Redis管理器设置密码!")

    def check_sqlite(self):
        if not public.ExecShell('{postconf} -m | grep sqlite'.format(postconf=get_postconf()))[0].strip():
            return public.returnMsg(False,"Postfix的Sqlite包异常,请检查")
        return public.returnMsg(True,"Postfix已支持Sqlite")

    def setup_rspamd(self):
        # public.print_log("进入修复文件1")
        # 修改postfix配置
        self.write_logs('|-Initializing rspamd...')
        edit_postfix_conf_shell = '''
{postconf} -e "smtpd_milters = inet:127.0.0.1:11332"
{postconf} -e "non_smtpd_milters = inet:127.0.0.1:11332"
{postconf} -e "milter_mail_macros = i {{mail_addr}} {{client_addr}} {{client_name}} {{auth_authen}}"
{postconf} -e "milter_protocol = 6"
{postconf} -e "milter_default_action = accept"
'''.format(postconf=get_postconf())
        public.ExecShell(edit_postfix_conf_shell)
        self.write_logs('|-Downloading additional configuration files...')
        get_rspamd_conf_shell = """
mkdir -p /usr/lib/dovecot/sieve
wget -O /etc/rspamd/worker-normal.inc {download_conf_url}/mail_sys/rspamd/worker-normal.inc -T 20 --no-check-certificate >> {logfile} 2>&1
wget -O /etc/rspamd/worker-fuzzy.inc {download_conf_url}/mail_sys/rspamd/worker-fuzzy.inc -T 20 --no-check-certificate >> {logfile} 2>&1
wget -O /etc/rspamd/statistic.conf {download_conf_url}/mail_sys/rspamd/statistic.conf -T 20 --no-check-certificate >> {logfile} 2>&1
wget -O /etc/rspamd/local.d/worker-controller.inc {download_conf_url}/mail_sys/rspamd/worker-controller.inc -T 20 --no-check-certificate >> {logfile} 2>&1
wget -O /etc/rspamd/worker-proxy.inc {download_conf_url}/mail_sys/rspamd/worker-proxy.inc -T 20 --no-check-certificate >> {logfile} 2>&1
wget -O /etc/rspamd/local.d/dkim_signing.conf {download_conf_url}/mail_sys/rspamd/modules.d/dkim_signing_bt.conf -T 20 --no-check-certificate >> {logfile} 2>&1
wget -O /etc/rspamd/local.d/milter_headers.conf {download_conf_url}/mail_sys/rspamd/modules.d/milter_headers_bt.conf -T 20 --no-check-certificate >> {logfile} 2>&1
wget -O /etc/rspamd/local.d/redis.conf {download_conf_url}/mail_sys/rspamd/modules.d/redis_bt.conf -T 20 --no-check-certificate >> {logfile} 2>&1

wget -O /usr/lib/dovecot/sieve/report-ham.sieve {download_conf_url}/mail_sys/dovecot/lib/report-ham.sieve -T 20 --no-check-certificate >> {logfile} 2>&1
wget -O /usr/lib/dovecot/sieve/report-spam.sieve {download_conf_url}/mail_sys/dovecot/lib/report-spam.sieve -T 20 --no-check-certificate >> {logfile} 2>&1
wget -O /usr/lib/dovecot/sieve/spam-to-folder.sieve {download_conf_url}/mail_sys/dovecot/lib/spam-to-folder.sieve -T 20 --no-check-certificate >> {logfile} 2>&1
wget -O /usr/lib/dovecot/sieve/sa-learn-spam.sh {download_conf_url}/mail_sys/dovecot/lib/sa-learn-spam.sh -T 20 --no-check-certificate >> {logfile} 2>&1
wget -O /usr/lib/dovecot/sieve/sa-learn-ham.sh {download_conf_url}/mail_sys/dovecot/lib/sa-learn-ham.sh -T 20 --no-check-certificate >> {logfile} 2>&1
sievec /usr/lib/dovecot/sieve/spam-to-folder.sieve
sievec /usr/lib/dovecot/sieve/report-spam.sieve
sievec /usr/lib/dovecot/sieve/report-ham.sieve
chmod +x /usr/lib/dovecot/sieve/sa-learn-spam.sh
chmod +x /usr/lib/dovecot/sieve/sa-learn-ham.sh
""".format(download_conf_url=download_url,logfile=self.logfile)
        public.ExecShell(get_rspamd_conf_shell)
        # 生成web端管理密码
        self.write_logs('|-Generating rspamd management password...')
        passwd = public.GetRandomString(8)
        passwd_en = public.ExecShell('rspamadm pw -p "{}"'.format(passwd))[0].strip('\n')
        public.writeFile('/etc/rspamd/passwd', passwd)
        worker_controller_path = '/etc/rspamd/local.d/worker-controller.inc'
        worker_controller = public.readFile(worker_controller_path)
        if worker_controller:
            if 'BT_PASSWORD' in worker_controller:
                worker_controller = worker_controller.replace('password = "BT_PASSWORD";',
                                                              'password = "{}";'.format(passwd_en))
                public.writeFile(worker_controller_path, worker_controller)
        # 设置rspamd redis密码
        rspamd_redis_path = '/etc/rspamd/local.d/redis.conf'
        rspamd_redis = public.readFile(rspamd_redis_path)
        if rspamd_redis:
            if 'BT_REDIS_PASSWD' in rspamd_redis:
                rspamd_redis = rspamd_redis.replace('password = "BT_REDIS_PASSWD";',
                                                    'password = "{}";'.format(self.get_redis_passwd()))
                public.writeFile(rspamd_redis_path, rspamd_redis)
        self.write_logs('|-Restarting rspamd...')
        public.ExecShell('systemctl restart rspamd postfix dovecot')
        return True

    def get_redis_passwd(self):
        redis_path = '/www/server/redis/redis.conf'
        redis_conf = public.readFile(redis_path)
        passwd = re.search('\n\s*requirepass\s+(.*)',redis_conf)
        if passwd:
            return passwd.groups(0)[0]
        return False

    def install_dovecot_on_ubuntu(self):
        install_shell = """
sudo apt remove dovecot-core dovecot-imapd dovecot-lmtpd dovecot-pop3d dovecot-sqlite dovecot-sieve -y
dpkg -P dovecot-core dovecot-imapd dovecot-lmtpd dovecot-pop3d dovecot-sqlite dovecot-sieve
sudo apt install dovecot-core dovecot-pop3d dovecot-imapd dovecot-lmtpd dovecot-sqlite dovecot-sieve -y
"""
        public.ExecShell(install_shell)
        shell_str = """
sudo rm -f /etc/pki/dovecot/certs/dovecot.pem
sudo rm -f /etc/pki/dovecot/private/dovecot.pem
sudo mkdir -p /etc/pki/dovecot/certs/
sudo mkdir -p /etc/pki/dovecot/private/
sudo cp /etc/ssl/certs/ssl-cert-snakeoil.pem /etc/pki/dovecot/certs/dovecot.pem
sudo mv /etc/ssl/private/ssl-cert-snakeoil.key /etc/pki/dovecot/private/dovecot.pem
"""
        public.ExecShell(shell_str)
        return self.conf_dovecot()

    def install_dovecot_on_centos7(self):
        install_shell = """
yum remove dovecot -y
yum install dovecot-pigeonhole -y
yum install dovecot -y
"""
        public.ExecShell(install_shell)
        return self.conf_dovecot()

    def install_dovecot_on_centos8(self):
        install_shell = """
yum remove dovecot -y
yum install dovecot-pigeonhole -y
yum install dovecot -y
"""
        public.ExecShell(install_shell)
        return self.conf_dovecot()

    def install_postfix_on_ubuntu(self):
        back_shell = ""
        restore_shell = ""
        if os.path.exists("/etc/postfix/main.cf"):
            back_shell = "mv /etc/postfix /etc/postfix_aap_bak"
            restore_shell = """
sudo rm -rf /etc/postfix
mv /etc/postfix_aap_bak /etc/postfix
"""
        install_shell = """
%s
sudo apt remove postfix postfix-sqlite -y
sudo dpkg -P postfix postfix-sqlite
sudo debconf-set-selections <<< "postfix postfix/mailname string ${hostname}"
sudo debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Internet Site'"
sudo apt install postfix -y
sudo apt install postfix-sqlite -y
sudo apt install sqlite -y
%s
""" % (back_shell,restore_shell)
        public.ExecShell(install_shell)

    def install_postfix_on_centos7(self):
        back_shell = ""
        restore_shell = ""
        if os.path.exists("/etc/postfix/main.cf"):
            back_shell = "mv /etc/postfix /etc/postfix_aap_bak"
            restore_shell = """
sudo rm -rf /etc/postfix
mv /etc/postfix_aap_bak /etc/postfix
"""
        install_shell = """
{b}
yum remove postfix -y
wget -O /tmp/postfix3-3.4.7-1.gf.el7.x86_64.rpm {download_conf_url}/install/plugin/mail_sys/rpm/postfix3-3.4.7-1.gf.el7.x86_64.rpm
yum localinstall /tmp/postfix3-3.4.7-1.gf.el7.x86_64.rpm -y
rm -f /tmp/postfix3-3.4.7-1.gf.el7.x86_64.rpm
wget -O /tmp/postfix3-sqlite-3.4.7-1.gf.el7.x86_64.rpm {download_conf_url}/install/plugin/mail_sys/rpm/postfix3-sqlite-3.4.7-1.gf.el7.x86_64.rpm
yum localinstall /tmp/postfix3-sqlite-3.4.7-1.gf.el7.x86_64.rpm -y
/tmp/postfix3-sqlite-3.4.7-1.gf.el7.x86_64.rpm
{r}
""".format(download_conf_url=download_url,b=back_shell,r=restore_shell)
        public.ExecShell(install_shell)

    def install_postfix_on_centos8(self):
        back_shell = ""
        restore_shell = ""
        if os.path.exists("/etc/postfix/main.cf"):
            back_shell = "mv /etc/postfix /etc/postfix_aap_bak"
            restore_shell = """
sudo rm -rf /etc/postfix
mv /etc/postfix_aap_bak /etc/postfix
"""
        install_shell = """
{b}
yum remove postfix -y
wget -O /tmp/postfix3-3.4.9-1.gf.el8.x86_64.rpm {download_conf_url}/install/plugin/mail_sys/rpm/postfix3-3.4.9-1.gf.el8.x86_64.rpm
yum localinstall /tmp/postfix3-3.4.9-1.gf.el8.x86_64.rpm -y
rm -f /tmp/postfix3-3.4.9-1.gf.el8.x86_64.rpm
wget -O /tmp/postfix3-sqlite-3.4.9-1.gf.el8.x86_64.rpm {download_conf_url}/install/plugin/mail_sys/rpm/postfix3-sqlite-3.4.9-1.gf.el8.x86_64.rpm
yum localinstall /tmp/postfix3-sqlite-3.4.9-1.gf.el8.x86_64.rpm -y
rm -f /tmp/postfix3-sqlite-3.4.9-1.gf.el8.x86_64.rpm
{r}
""".format(download_conf_url=download_url,b=back_shell,r=restore_shell)
        public.ExecShell(install_shell)

if __name__ == '__main__':
    args = sys.argv
    if len(args) > 1:
        if args[1] == 'change_to_rspamd':
            change_to_rspamd().main()
        elif args[1] == 'setup_mail_sys':
            print(mail_server_init().setup_mail_sys(args))
        elif args[1] == 'check_env':
            print(mail_server_init().check_env())
        elif args[1] == 'install_dovecot_on_ubuntu':
            print(mail_server_init().install_dovecot_on_ubuntu())
        elif args[1] == 'install_dovecot_on_centos7':
            print(mail_server_init().install_dovecot_on_centos7())
        elif args[1] == 'install_dovecot_on_centos8':
            print(mail_server_init().install_dovecot_on_centos8())
        elif args[1] == 'install_postfix_on_ubuntu':
            print(mail_server_init().install_postfix_on_ubuntu())
        elif args[1] == 'install_postfix_on_centos7':
            print(mail_server_init().install_postfix_on_centos7())
        elif args[1] == 'install_postfix_on_centos8':
            print(mail_server_init().install_postfix_on_centos8())
        else:
            print('args error')
    else:
        print('args error')