From ff91d93a2d88fefceb15eb8974624c371ee03ff6 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 7 Jul 2006 15:57:03 +0000 Subject: [PATCH] initial 2.0 tree trunk git-svn-id: svn://192.168.202.10@18 3d104415-ff17-0410-8863-d5cf3c621b8a --- ADMIN_adjust_GMTnow_on_leads.pl | 688 ++ ADMIN_area_code_populate.pl | 67 + ADMIN_keepalive_AST_VDautodial.pl | 120 + ADMIN_keepalive_AST_VDremote_agents.pl | 119 + ADMIN_keepalive_AST_send_listen.pl | 169 + ADMIN_keepalive_AST_update.pl | 121 + ADMIN_keepalive_send_listen.at | 6 + ADMIN_restart_roll_logs.pl | 52 + AST_CRON_mix_recordings.pl | 124 + AST_CRON_mix_recordings_BASIC.pl | 100 + AST_CRON_mix_recordings_GSM.pl | 151 + AST_CRON_mix_recordings_MP3.pl | 152 + AST_DB_optimize.pl | 153 + AST_SERVER_conf.pl | 25 + AST_VDauto_dial.pl | 887 +++ AST_VDhopper.pl | 1192 +++ AST_VDremote_agents.pl | 493 ++ AST_agent_week.pl | 336 + AST_cleanup_agent_log.pl | 236 + AST_conf_update.pl | 220 + AST_flush_DBqueue.pl | 189 + AST_manager_kill_hung_congested.pl | 335 + AST_manager_listen.pl | 594 ++ AST_manager_send.pl | 384 + AST_reset_mysql_vars.pl | 72 + AST_send_action_child.pl | 258 + AST_update.pl | 1110 +++ AST_vm_update.pl | 202 + DBI-scripts/AST_VDhopper.pl | 1188 +++ DBI-scripts/AST_agent_week.pl | 336 + DTMF_sounds/0.gsm | Bin 0 -> 429 bytes DTMF_sounds/0.wav | Bin 0 -> 4100 bytes DTMF_sounds/1.gsm | 1 + DTMF_sounds/1.wav | Bin 0 -> 4100 bytes DTMF_sounds/2.gsm | 3 + DTMF_sounds/2.wav | Bin 0 -> 4018 bytes DTMF_sounds/3.gsm | 2 + DTMF_sounds/3.wav | Bin 0 -> 4046 bytes DTMF_sounds/4.gsm | 2 + DTMF_sounds/4.wav | Bin 0 -> 3990 bytes DTMF_sounds/5.gsm | 1 + DTMF_sounds/5.wav | Bin 0 -> 3990 bytes DTMF_sounds/6.gsm | 1 + DTMF_sounds/6.wav | Bin 0 -> 4046 bytes DTMF_sounds/7.gsm | 2 + DTMF_sounds/7.wav | Bin 0 -> 4072 bytes DTMF_sounds/8.gsm | Bin 0 -> 429 bytes DTMF_sounds/8.wav | Bin 0 -> 4018 bytes DTMF_sounds/9.gsm | Bin 0 -> 429 bytes DTMF_sounds/9.wav | Bin 0 -> 4018 bytes DTMF_sounds/US_pol_survey_hello.gsm | Bin 0 -> 55737 bytes DTMF_sounds/US_pol_survey_transfer.gsm | Bin 0 -> 10461 bytes DTMF_sounds/US_reminder_callback.gsm | Bin 0 -> 5610 bytes DTMF_sounds/US_reminder_goodbye.gsm | Bin 0 -> 1980 bytes DTMF_sounds/US_reminder_message.gsm | Bin 0 -> 14058 bytes DTMF_sounds/US_reminder_options.gsm | Bin 0 -> 11748 bytes DTMF_sounds/US_thanks_no_contact.gsm | Bin 0 -> 3894 bytes DTMF_sounds/auth-thankyou.gsm | Bin 0 -> 1947 bytes DTMF_sounds/buzz.gsm | Bin 0 -> 363 bytes DTMF_sounds/ding.gsm | Bin 0 -> 363 bytes DTMF_sounds/enter.gsm | Bin 0 -> 231 bytes DTMF_sounds/four_digit_id.gsm | Bin 0 -> 2211 bytes DTMF_sounds/generic_hold.gsm | Bin 0 -> 8250 bytes DTMF_sounds/hash.gsm | 2 + DTMF_sounds/hash.wav | Bin 0 -> 3990 bytes DTMF_sounds/hold_tone.gsm | Bin 0 -> 759 bytes DTMF_sounds/ld_invalid_pin_number.gsm | Bin 0 -> 2772 bytes DTMF_sounds/ld_welcome_pin_number.gsm | Bin 0 -> 4587 bytes DTMF_sounds/leave.gsm | Bin 0 -> 330 bytes DTMF_sounds/silence.wav | Bin 0 -> 8044 bytes DTMF_sounds/star.gsm | 2 + DTMF_sounds/star.wav | Bin 0 -> 4124 bytes DTMF_sounds/vm-goodbye.gsm | Bin 0 -> 1419 bytes DTMF_sounds/vm-msgsaved.gsm | Bin 0 -> 3168 bytes DTMF_sounds/vm-rec-generic.gsm | Bin 0 -> 6534 bytes DTMF_sounds/vm-review.gsm | Bin 0 -> 14487 bytes LANG_admin.zip | Bin 0 -> 898540 bytes .../astguiclient/AST_inboundEXTstats.php | 400 + LANG_admin/astguiclient/admin.php | 1824 +++++ LANG_admin/astguiclient/dbconnect.php | 15 + LANG_admin/astguiclient/help.gif | Bin 0 -> 492 bytes LANG_admin/astguiclient/inbound_popup.php | 228 + LANG_admin/astguiclient/phone_stats.php | 244 + LANG_admin/astguiclient/remote_inbound.php | 162 + LANG_admin/astguiclient/test.php | 30 + .../astguiclient_de/AST_inboundEXTstats.php | 400 + LANG_admin/astguiclient_de/admin.php | 1824 +++++ LANG_admin/astguiclient_de/dbconnect.php | 15 + LANG_admin/astguiclient_de/help.gif | Bin 0 -> 492 bytes LANG_admin/astguiclient_de/inbound_popup.php | 228 + LANG_admin/astguiclient_de/phone_stats.php | 244 + LANG_admin/astguiclient_de/remote_inbound.php | 162 + .../astguiclient_el/AST_inboundEXTstats.php | 400 + LANG_admin/astguiclient_el/admin.php | 1824 +++++ LANG_admin/astguiclient_el/dbconnect.php | 15 + LANG_admin/astguiclient_el/help.gif | Bin 0 -> 492 bytes LANG_admin/astguiclient_el/inbound_popup.php | 228 + LANG_admin/astguiclient_el/phone_stats.php | 244 + LANG_admin/astguiclient_el/remote_inbound.php | 162 + .../astguiclient_en/AST_inboundEXTstats.php | 400 + LANG_admin/astguiclient_en/admin.php | 1824 +++++ LANG_admin/astguiclient_en/dbconnect.php | 16 + LANG_admin/astguiclient_en/help.gif | Bin 0 -> 492 bytes LANG_admin/astguiclient_en/inbound_popup.php | 228 + LANG_admin/astguiclient_en/phone_stats.php | 244 + LANG_admin/astguiclient_en/remote_inbound.php | 162 + .../astguiclient_es/AST_inboundEXTstats.php | 400 + LANG_admin/astguiclient_es/admin.php | 1824 +++++ LANG_admin/astguiclient_es/dbconnect.php | 15 + LANG_admin/astguiclient_es/help.gif | Bin 0 -> 492 bytes LANG_admin/astguiclient_es/inbound_popup.php | 228 + LANG_admin/astguiclient_es/phone_stats.php | 244 + LANG_admin/astguiclient_es/remote_inbound.php | 162 + LANG_admin/vicidial/AST_CLOSERstats.php | 396 + LANG_admin/vicidial/AST_VDADstats.php | 417 ++ .../vicidial/AST_VICIDIAL_hopperlist.php | 161 + LANG_admin/vicidial/AST_admin_log_display.php | 118 + LANG_admin/vicidial/AST_agent_performance.php | 232 + .../vicidial/AST_agent_performance_detail.php | 406 + LANG_admin/vicidial/AST_agent_time_sheet.php | 281 + .../vicidial/AST_agent_time_sheet_archive.php | 281 + LANG_admin/vicidial/AST_parkstats.php | 396 + .../vicidial/AST_server_performance.php | 310 + LANG_admin/vicidial/AST_timeonVDAD.php | 255 + LANG_admin/vicidial/AST_timeonVDAD_closer.php | 316 + LANG_admin/vicidial/AST_timeonVDADall.php | 349 + .../vicidial/AST_timeonVDADall_SIPmonitor.php | 301 + LANG_admin/vicidial/AST_timeoncall.php | 180 + LANG_admin/vicidial/AST_timeonpark.php | 197 + LANG_admin/vicidial/admin-old.php | 2289 ++++++ LANG_admin/vicidial/admin.php | 6514 +++++++++++++++++ LANG_admin/vicidial/admin_modify_lead.php | 476 ++ LANG_admin/vicidial/admin_search_lead.php | 224 + LANG_admin/vicidial/closer-fronter_popup.php | 508 ++ LANG_admin/vicidial/closer-fronter_popup2.php | 423 ++ LANG_admin/vicidial/closer.php | 345 + LANG_admin/vicidial/closer_dispo.php | 329 + LANG_admin/vicidial/closer_popup.php | 445 ++ LANG_admin/vicidial/count.htm | 1 + LANG_admin/vicidial/dbconnect.php | 15 + LANG_admin/vicidial/group_hourly_stats.php | 252 + LANG_admin/vicidial/help.gif | Bin 0 -> 492 bytes LANG_admin/vicidial/listloader.php | 698 ++ LANG_admin/vicidial/listloader.pl | 690 ++ LANG_admin/vicidial/listloaderMAIN.php | 79 + LANG_admin/vicidial/listloader_rowdisplay.pl | 56 + LANG_admin/vicidial/listloader_super.pl | 691 ++ LANG_admin/vicidial/log_test.php | 37 + LANG_admin/vicidial/new_listloader_superL.php | 1364 ++++ LANG_admin/vicidial/record_conf_1_hour.php | 156 + LANG_admin/vicidial/remote_dispo.php | 327 + LANG_admin/vicidial/server_stats.php | 96 + LANG_admin/vicidial/test.txt | 1 + LANG_admin/vicidial/user_stats.php | 316 + LANG_admin/vicidial/user_status.php | 238 + LANG_admin/vicidial/vdremote.php | 602 ++ LANG_admin/vicidial_de/AST_CLOSERstats.php | 396 + LANG_admin/vicidial_de/AST_VDADstats.php | 417 ++ .../vicidial_de/AST_VICIDIAL_hopperlist.php | 161 + .../vicidial_de/AST_admin_log_display.php | 118 + .../vicidial_de/AST_agent_performance.php | 232 + .../AST_agent_performance_detail.php | 406 + .../vicidial_de/AST_agent_time_sheet.php | 281 + .../vicidial_de/AST_server_performance.php | 310 + LANG_admin/vicidial_de/AST_timeonVDAD.php | 255 + .../vicidial_de/AST_timeonVDAD_closer.php | 316 + LANG_admin/vicidial_de/AST_timeonVDADall.php | 349 + .../AST_timeonVDADall_SIPmonitor.php | 301 + LANG_admin/vicidial_de/AST_timeoncall.php | 180 + LANG_admin/vicidial_de/AST_timeonpark.php | 197 + LANG_admin/vicidial_de/admin.php | 6514 +++++++++++++++++ LANG_admin/vicidial_de/admin_modify_lead.php | 476 ++ LANG_admin/vicidial_de/admin_search_lead.php | 224 + LANG_admin/vicidial_de/count.htm | 1 + LANG_admin/vicidial_de/dbconnect.php | 15 + LANG_admin/vicidial_de/group_hourly_stats.php | 252 + LANG_admin/vicidial_de/help.gif | Bin 0 -> 492 bytes LANG_admin/vicidial_de/listloader.php | 698 ++ LANG_admin/vicidial_de/listloaderMAIN.php | 79 + .../vicidial_de/new_listloader_superL.php | 1364 ++++ LANG_admin/vicidial_de/remote_dispo.php | 327 + LANG_admin/vicidial_de/server_stats.php | 96 + LANG_admin/vicidial_de/user_stats.php | 316 + LANG_admin/vicidial_de/user_status.php | 238 + LANG_admin/vicidial_de/vdremote.php | 602 ++ LANG_admin/vicidial_el/AST_CLOSERstats.php | 396 + LANG_admin/vicidial_el/AST_VDADstats.php | 417 ++ .../vicidial_el/AST_VICIDIAL_hopperlist.php | 161 + .../vicidial_el/AST_admin_log_display.php | 118 + .../vicidial_el/AST_agent_performance.php | 232 + .../AST_agent_performance_detail.php | 406 + .../vicidial_el/AST_agent_time_sheet.php | 281 + .../vicidial_el/AST_server_performance.php | 310 + LANG_admin/vicidial_el/AST_timeonVDAD.php | 255 + .../vicidial_el/AST_timeonVDAD_closer.php | 316 + LANG_admin/vicidial_el/AST_timeonVDADall.php | 349 + .../AST_timeonVDADall_SIPmonitor.php | 282 + LANG_admin/vicidial_el/AST_timeoncall.php | 180 + LANG_admin/vicidial_el/AST_timeonpark.php | 197 + LANG_admin/vicidial_el/admin.php | 6514 +++++++++++++++++ LANG_admin/vicidial_el/admin_modify_lead.php | 476 ++ LANG_admin/vicidial_el/admin_search_lead.php | 224 + LANG_admin/vicidial_el/count.htm | 1 + LANG_admin/vicidial_el/dbconnect.php | 16 + LANG_admin/vicidial_el/group_hourly_stats.php | 252 + LANG_admin/vicidial_el/help.gif | Bin 0 -> 492 bytes LANG_admin/vicidial_el/htglobalize.php | 23 + LANG_admin/vicidial_el/listloader.php | 698 ++ LANG_admin/vicidial_el/listloaderMAIN.php | 79 + LANG_admin/vicidial_el/listloader_stmts.txt | 0 .../vicidial_el/new_listloader_superL.php | 1364 ++++ .../vicidial_el/project_auth_entries.txt | 114 + LANG_admin/vicidial_el/remote_dispo.php | 327 + LANG_admin/vicidial_el/server_stats.php | 96 + LANG_admin/vicidial_el/user_stats.php | 316 + LANG_admin/vicidial_el/user_status.php | 238 + LANG_admin/vicidial_el/vdremote.php | 602 ++ LANG_admin/vicidial_en/AST_CLOSERstats.php | 396 + LANG_admin/vicidial_en/AST_VDADstats.php | 417 ++ .../vicidial_en/AST_VICIDIAL_hopperlist.php | 161 + .../vicidial_en/AST_admin_log_display.php | 118 + .../vicidial_en/AST_agent_performance.php | 232 + .../AST_agent_performance_detail.php | 406 + .../vicidial_en/AST_agent_time_sheet.php | 281 + .../vicidial_en/AST_server_performance.php | 310 + LANG_admin/vicidial_en/AST_timeonVDAD.php | 255 + .../vicidial_en/AST_timeonVDAD_closer.php | 316 + LANG_admin/vicidial_en/AST_timeonVDADall.php | 349 + .../AST_timeonVDADall_SIPmonitor.php | 301 + LANG_admin/vicidial_en/AST_timeoncall.php | 180 + LANG_admin/vicidial_en/AST_timeonpark.php | 197 + LANG_admin/vicidial_en/admin.php | 6514 +++++++++++++++++ LANG_admin/vicidial_en/admin_changes_log.txt | 37 + LANG_admin/vicidial_en/admin_modify_lead.php | 476 ++ LANG_admin/vicidial_en/admin_search_lead.php | 224 + LANG_admin/vicidial_en/count.htm | 1 + LANG_admin/vicidial_en/dbconnect.php | 15 + LANG_admin/vicidial_en/group_hourly_stats.php | 252 + LANG_admin/vicidial_en/help.gif | Bin 0 -> 492 bytes LANG_admin/vicidial_en/listloader.php | 698 ++ LANG_admin/vicidial_en/listloaderMAIN.php | 79 + .../vicidial_en/new_listloader_superL.php | 1364 ++++ .../vicidial_en/project_auth_entries.txt | 129 + LANG_admin/vicidial_en/remote_dispo.php | 327 + LANG_admin/vicidial_en/server_stats.php | 96 + LANG_admin/vicidial_en/user_stats.php | 316 + LANG_admin/vicidial_en/user_status.php | 238 + LANG_admin/vicidial_en/vdremote.php | 602 ++ LANG_admin/vicidial_es/AST_CLOSERstats.php | 396 + LANG_admin/vicidial_es/AST_VDADstats.php | 417 ++ .../vicidial_es/AST_VICIDIAL_hopperlist.php | 161 + .../vicidial_es/AST_admin_log_display.php | 118 + .../vicidial_es/AST_agent_performance.php | 232 + .../AST_agent_performance_detail.php | 406 + .../vicidial_es/AST_agent_time_sheet.php | 281 + .../vicidial_es/AST_server_performance.php | 310 + LANG_admin/vicidial_es/AST_timeonVDAD.php | 255 + .../vicidial_es/AST_timeonVDAD_closer.php | 316 + LANG_admin/vicidial_es/AST_timeonVDADall.php | 349 + .../AST_timeonVDADall_SIPmonitor.php | 301 + LANG_admin/vicidial_es/AST_timeoncall.php | 180 + LANG_admin/vicidial_es/AST_timeonpark.php | 197 + LANG_admin/vicidial_es/admin.php | 6514 +++++++++++++++++ LANG_admin/vicidial_es/admin_changes_log.txt | 5 + LANG_admin/vicidial_es/admin_modify_lead.php | 476 ++ LANG_admin/vicidial_es/admin_search_lead.php | 224 + LANG_admin/vicidial_es/count.htm | 1 + LANG_admin/vicidial_es/dbconnect.php | 15 + LANG_admin/vicidial_es/group_hourly_stats.php | 252 + LANG_admin/vicidial_es/help.gif | Bin 0 -> 492 bytes LANG_admin/vicidial_es/listloader.php | 698 ++ LANG_admin/vicidial_es/listloaderMAIN.php | 79 + .../vicidial_es/new_listloader_superL.php | 1364 ++++ .../vicidial_es/project_auth_entries.txt | 170 + LANG_admin/vicidial_es/remote_dispo.php | 327 + LANG_admin/vicidial_es/server_stats.php | 96 + LANG_admin/vicidial_es/user_stats.php | 316 + LANG_admin/vicidial_es/user_status.php | 238 + LANG_admin/vicidial_es/vdremote.php | 602 ++ LANG_agc.zip | Bin 0 -> 1058823 bytes LANG_agc/agc/active_list_refresh.php | 463 ++ LANG_agc/agc/astguiclient.php | 2890 ++++++++ LANG_agc/agc/calendar.php | 125 + LANG_agc/agc/call_log_display.php | 192 + LANG_agc/agc/conf_exten_check.php | 258 + LANG_agc/agc/dbconnect.php | 15 + LANG_agc/agc/fix-dispo-list.patch | 73 + .../agc/images/agc_check_voicemail_BLINK.gif | Bin 0 -> 2627 bytes .../images/agc_check_voicemail_BLINK_e.gif | Bin 0 -> 780 bytes .../images/agc_check_voicemail_BLINK_es.gif | Bin 0 -> 780 bytes .../images/agc_check_voicemail_BLINK_ptbr.gif | Bin 0 -> 886 bytes .../agc/images/agc_check_voicemail_OFF.gif | Bin 0 -> 919 bytes .../agc/images/agc_check_voicemail_OFF_es.gif | Bin 0 -> 785 bytes .../images/agc_check_voicemail_OFF_ptbr.gif | Bin 0 -> 880 bytes .../agc/images/agc_check_voicemail_ON.gif | Bin 0 -> 919 bytes .../agc/images/agc_check_voicemail_ON_es.gif | Bin 0 -> 781 bytes .../images/agc_check_voicemail_ON_ptbr.gif | Bin 0 -> 881 bytes LANG_agc/agc/images/agc_live_call_OFF.gif | Bin 0 -> 541 bytes LANG_agc/agc/images/agc_live_call_OFF_es.gif | Bin 0 -> 513 bytes .../agc/images/agc_live_call_OFF_ptbr.gif | Bin 0 -> 459 bytes LANG_agc/agc/images/agc_live_call_ON.gif | Bin 0 -> 793 bytes LANG_agc/agc/images/agc_live_call_ON_es.gif | Bin 0 -> 871 bytes LANG_agc/agc/images/agc_live_call_ON_ptbr.gif | Bin 0 -> 2750 bytes LANG_agc/agc/images/agc_tab_active_lines.gif | Bin 0 -> 886 bytes .../agc/images/agc_tab_active_lines_es.gif | Bin 0 -> 704 bytes .../agc/images/agc_tab_active_lines_ptbr.gif | Bin 0 -> 1005 bytes LANG_agc/agc/images/agc_tab_astguiclient.gif | Bin 0 -> 1092 bytes .../agc/images/agc_tab_astguiclient_ptbr.gif | Bin 0 -> 1092 bytes LANG_agc/agc/images/agc_tab_conferences.gif | Bin 0 -> 928 bytes .../agc/images/agc_tab_conferences_es.gif | Bin 0 -> 718 bytes .../agc/images/agc_tab_conferences_ptbr.gif | Bin 0 -> 718 bytes LANG_agc/agc/images/agc_tab_main.gif | Bin 0 -> 596 bytes LANG_agc/agc/images/agc_tab_main_es.gif | Bin 0 -> 541 bytes LANG_agc/agc/images/agc_tab_main_ptbr.gif | Bin 0 -> 541 bytes LANG_agc/agc/images/blank.gif | Bin 0 -> 43 bytes LANG_agc/agc/images/br.gif | Bin 0 -> 397 bytes LANG_agc/agc/images/de.gif | Bin 0 -> 162 bytes LANG_agc/agc/images/down.gif | Bin 0 -> 169 bytes LANG_agc/agc/images/el.gif | Bin 0 -> 245 bytes LANG_agc/agc/images/en.gif | Bin 0 -> 322 bytes LANG_agc/agc/images/es.gif | Bin 0 -> 222 bytes LANG_agc/agc/images/fr.gif | Bin 0 -> 217 bytes LANG_agc/agc/images/it.gif | Bin 0 -> 198 bytes LANG_agc/agc/images/pt.gif | Bin 0 -> 208 bytes LANG_agc/agc/images/remove.gif | Bin 0 -> 176 bytes LANG_agc/agc/images/up.gif | Bin 0 -> 169 bytes LANG_agc/agc/images/vdc_LB_dialnextnumber.gif | Bin 0 -> 831 bytes .../agc/images/vdc_LB_dialnextnumber_OFF.gif | Bin 0 -> 827 bytes .../images/vdc_LB_dialnextnumber_OFF_es.gif | Bin 0 -> 914 bytes .../images/vdc_LB_dialnextnumber_OFF_ptbr.gif | Bin 0 -> 961 bytes .../agc/images/vdc_LB_dialnextnumber_es.gif | Bin 0 -> 914 bytes .../agc/images/vdc_LB_dialnextnumber_ptbr.gif | Bin 0 -> 965 bytes LANG_agc/agc/images/vdc_LB_grabparkedcall.gif | Bin 0 -> 804 bytes .../agc/images/vdc_LB_grabparkedcall_OFF.gif | Bin 0 -> 802 bytes .../images/vdc_LB_grabparkedcall_OFF_es.gif | Bin 0 -> 827 bytes .../images/vdc_LB_grabparkedcall_OFF_ptbr.gif | Bin 0 -> 981 bytes .../agc/images/vdc_LB_grabparkedcall_es.gif | Bin 0 -> 826 bytes .../agc/images/vdc_LB_grabparkedcall_ptbr.gif | Bin 0 -> 985 bytes LANG_agc/agc/images/vdc_LB_hangupcustomer.gif | Bin 0 -> 803 bytes .../agc/images/vdc_LB_hangupcustomer_OFF.gif | Bin 0 -> 803 bytes .../images/vdc_LB_hangupcustomer_OFF_es.gif | Bin 0 -> 693 bytes .../images/vdc_LB_hangupcustomer_OFF_ptbr.gif | Bin 0 -> 811 bytes .../agc/images/vdc_LB_hangupcustomer_es.gif | Bin 0 -> 697 bytes .../agc/images/vdc_LB_hangupcustomer_ptbr.gif | Bin 0 -> 1029 bytes LANG_agc/agc/images/vdc_LB_parkcall.gif | Bin 0 -> 601 bytes LANG_agc/agc/images/vdc_LB_parkcall_OFF.gif | Bin 0 -> 607 bytes .../agc/images/vdc_LB_parkcall_OFF_es.gif | Bin 0 -> 644 bytes .../agc/images/vdc_LB_parkcall_OFF_ptbr.gif | Bin 0 -> 830 bytes LANG_agc/agc/images/vdc_LB_parkcall_es.gif | Bin 0 -> 646 bytes LANG_agc/agc/images/vdc_LB_parkcall_ptbr.gif | Bin 0 -> 858 bytes LANG_agc/agc/images/vdc_LB_pause.gif | Bin 0 -> 483 bytes LANG_agc/agc/images/vdc_LB_pause_OFF.gif | Bin 0 -> 483 bytes LANG_agc/agc/images/vdc_LB_pause_OFF_es.gif | Bin 0 -> 404 bytes LANG_agc/agc/images/vdc_LB_pause_OFF_ptbr.gif | Bin 0 -> 438 bytes LANG_agc/agc/images/vdc_LB_pause_es.gif | Bin 0 -> 410 bytes LANG_agc/agc/images/vdc_LB_pause_ptbr.gif | Bin 0 -> 989 bytes LANG_agc/agc/images/vdc_LB_resume.gif | Bin 0 -> 535 bytes LANG_agc/agc/images/vdc_LB_resume_OFF.gif | Bin 0 -> 533 bytes LANG_agc/agc/images/vdc_LB_resume_OFF_es.gif | Bin 0 -> 495 bytes .../agc/images/vdc_LB_resume_OFF_ptbr.gif | Bin 0 -> 416 bytes LANG_agc/agc/images/vdc_LB_resume_es.gif | Bin 0 -> 500 bytes LANG_agc/agc/images/vdc_LB_resume_ptbr.gif | Bin 0 -> 394 bytes LANG_agc/agc/images/vdc_LB_senddtmf.gif | Bin 0 -> 567 bytes LANG_agc/agc/images/vdc_LB_senddtmf_OFF.gif | Bin 0 -> 563 bytes .../agc/images/vdc_LB_senddtmf_OFF_es.gif | Bin 0 -> 563 bytes .../agc/images/vdc_LB_senddtmf_OFF_ptbr.gif | Bin 0 -> 563 bytes LANG_agc/agc/images/vdc_LB_senddtmf_es.gif | Bin 0 -> 564 bytes LANG_agc/agc/images/vdc_LB_senddtmf_ptbr.gif | Bin 0 -> 564 bytes LANG_agc/agc/images/vdc_LB_spacer.gif | Bin 0 -> 90 bytes LANG_agc/agc/images/vdc_LB_startrecording.gif | Bin 0 -> 778 bytes .../agc/images/vdc_LB_startrecording_OFF.gif | Bin 0 -> 778 bytes .../images/vdc_LB_startrecording_OFF_es.gif | Bin 0 -> 788 bytes .../images/vdc_LB_startrecording_OFF_ptbr.gif | Bin 0 -> 783 bytes .../agc/images/vdc_LB_startrecording_es.gif | Bin 0 -> 788 bytes .../agc/images/vdc_LB_startrecording_ptbr.gif | Bin 0 -> 784 bytes LANG_agc/agc/images/vdc_LB_stoprecording.gif | Bin 0 -> 758 bytes .../agc/images/vdc_LB_stoprecording_OFF.gif | Bin 0 -> 757 bytes .../images/vdc_LB_stoprecording_OFF_es.gif | Bin 0 -> 701 bytes .../images/vdc_LB_stoprecording_OFF_ptbr.gif | Bin 0 -> 778 bytes .../agc/images/vdc_LB_stoprecording_es.gif | Bin 0 -> 699 bytes .../agc/images/vdc_LB_stoprecording_ptbr.gif | Bin 0 -> 779 bytes LANG_agc/agc/images/vdc_LB_transferconf.gif | Bin 0 -> 732 bytes .../agc/images/vdc_LB_transferconf_OFF.gif | Bin 0 -> 732 bytes .../agc/images/vdc_LB_transferconf_OFF_es.gif | Bin 0 -> 712 bytes .../images/vdc_LB_transferconf_OFF_ptbr.gif | Bin 0 -> 896 bytes .../agc/images/vdc_LB_transferconf_es.gif | Bin 0 -> 714 bytes .../agc/images/vdc_LB_transferconf_ptbr.gif | Bin 0 -> 898 bytes LANG_agc/agc/images/vdc_LB_webform.gif | Bin 0 -> 542 bytes LANG_agc/agc/images/vdc_LB_webform_OFF.gif | Bin 0 -> 615 bytes LANG_agc/agc/images/vdc_LB_webform_OFF_es.gif | Bin 0 -> 661 bytes .../agc/images/vdc_LB_webform_OFF_ptbr.gif | Bin 0 -> 661 bytes LANG_agc/agc/images/vdc_LB_webform_es.gif | Bin 0 -> 583 bytes LANG_agc/agc/images/vdc_LB_webform_ptbr.gif | Bin 0 -> 583 bytes LANG_agc/agc/images/vdc_XB_ammessage.gif | Bin 0 -> 396 bytes LANG_agc/agc/images/vdc_XB_ammessage_OFF.gif | Bin 0 -> 403 bytes LANG_agc/agc/images/vdc_XB_blindtransfer.gif | Bin 0 -> 774 bytes .../agc/images/vdc_XB_blindtransfer_OFF.gif | Bin 0 -> 774 bytes .../images/vdc_XB_blindtransfer_OFF_es.gif | Bin 0 -> 758 bytes .../images/vdc_XB_blindtransfer_OFF_ptbr.gif | Bin 0 -> 901 bytes .../agc/images/vdc_XB_blindtransfer_es.gif | Bin 0 -> 758 bytes .../agc/images/vdc_XB_blindtransfer_ptbr.gif | Bin 0 -> 901 bytes LANG_agc/agc/images/vdc_XB_channel.gif | Bin 0 -> 314 bytes LANG_agc/agc/images/vdc_XB_channel_es.gif | Bin 0 -> 242 bytes LANG_agc/agc/images/vdc_XB_channel_ptbr.gif | Bin 0 -> 242 bytes LANG_agc/agc/images/vdc_XB_code.gif | Bin 0 -> 247 bytes .../agc/images/vdc_XB_dialwithcustomer.gif | Bin 0 -> 881 bytes .../images/vdc_XB_dialwithcustomer_OFF.gif | Bin 0 -> 881 bytes .../images/vdc_XB_dialwithcustomer_OFF_es.gif | Bin 0 -> 776 bytes .../vdc_XB_dialwithcustomer_OFF_ptbr.gif | Bin 0 -> 873 bytes .../agc/images/vdc_XB_dialwithcustomer_es.gif | Bin 0 -> 776 bytes .../images/vdc_XB_dialwithcustomer_ptbr.gif | Bin 0 -> 873 bytes .../agc/images/vdc_XB_hangupbothlines.gif | Bin 0 -> 849 bytes .../agc/images/vdc_XB_hangupbothlines_OFF.gif | Bin 0 -> 849 bytes .../images/vdc_XB_hangupbothlines_OFF_es.gif | Bin 0 -> 809 bytes .../vdc_XB_hangupbothlines_OFF_ptbr.gif | Bin 0 -> 858 bytes .../agc/images/vdc_XB_hangupbothlines_es.gif | Bin 0 -> 809 bytes .../images/vdc_XB_hangupbothlines_ptbr.gif | Bin 0 -> 858 bytes LANG_agc/agc/images/vdc_XB_hangupxferline.gif | Bin 0 -> 803 bytes .../agc/images/vdc_XB_hangupxferline_OFF.gif | Bin 0 -> 803 bytes .../images/vdc_XB_hangupxferline_OFF_es.gif | Bin 0 -> 702 bytes .../images/vdc_XB_hangupxferline_OFF_ptbr.gif | Bin 0 -> 828 bytes .../agc/images/vdc_XB_hangupxferline_es.gif | Bin 0 -> 702 bytes .../agc/images/vdc_XB_hangupxferline_ptbr.gif | Bin 0 -> 828 bytes LANG_agc/agc/images/vdc_XB_header.gif | Bin 0 -> 884 bytes LANG_agc/agc/images/vdc_XB_header_es.gif | Bin 0 -> 639 bytes LANG_agc/agc/images/vdc_XB_header_ptbr.gif | Bin 0 -> 639 bytes LANG_agc/agc/images/vdc_XB_hotkeysactive.gif | Bin 0 -> 791 bytes .../agc/images/vdc_XB_hotkeysactive_OFF.gif | Bin 0 -> 786 bytes .../vdc_XB_hotkeysactive_OFF_es-orig.gif | Bin 0 -> 1231 bytes .../images/vdc_XB_hotkeysactive_OFF_es.gif | Bin 0 -> 1256 bytes .../images/vdc_XB_hotkeysactive_OFF_ptbr.gif | Bin 0 -> 948 bytes .../agc/images/vdc_XB_hotkeysactive_es.gif | Bin 0 -> 1231 bytes .../agc/images/vdc_XB_hotkeysactive_ptbr.gif | Bin 0 -> 997 bytes .../agc/images/vdc_XB_hotkeysinactive_es.gif | Bin 0 -> 1256 bytes LANG_agc/agc/images/vdc_XB_internalcloser.gif | Bin 0 -> 801 bytes .../agc/images/vdc_XB_internalcloser_OFF.gif | Bin 0 -> 801 bytes .../images/vdc_XB_internalcloser_OFF_es.gif | Bin 0 -> 640 bytes .../images/vdc_XB_internalcloser_OFF_ptbr.gif | Bin 0 -> 640 bytes .../agc/images/vdc_XB_internalcloser_es.gif | Bin 0 -> 640 bytes .../agc/images/vdc_XB_internalcloser_ptbr.gif | Bin 0 -> 640 bytes LANG_agc/agc/images/vdc_XB_leave3waycall.gif | Bin 0 -> 816 bytes .../agc/images/vdc_XB_leave3waycall_OFF.gif | Bin 0 -> 816 bytes .../images/vdc_XB_leave3waycall_OFF_es.gif | Bin 0 -> 834 bytes .../images/vdc_XB_leave3waycall_OFF_ptbr.gif | Bin 0 -> 816 bytes .../agc/images/vdc_XB_leave3waycall_es.gif | Bin 0 -> 834 bytes .../agc/images/vdc_XB_leave3waycall_ptbr.gif | Bin 0 -> 816 bytes LANG_agc/agc/images/vdc_XB_localcloser.gif | Bin 0 -> 728 bytes .../agc/images/vdc_XB_localcloser_OFF.gif | Bin 0 -> 728 bytes .../agc/images/vdc_XB_localcloser_OFF_es.gif | Bin 0 -> 607 bytes .../images/vdc_XB_localcloser_OFF_ptbr.gif | Bin 0 -> 607 bytes LANG_agc/agc/images/vdc_XB_localcloser_es.gif | Bin 0 -> 606 bytes .../agc/images/vdc_XB_localcloser_ptbr.gif | Bin 0 -> 606 bytes LANG_agc/agc/images/vdc_XB_number.gif | Bin 0 -> 480 bytes LANG_agc/agc/images/vdc_XB_number_es.gif | Bin 0 -> 416 bytes LANG_agc/agc/images/vdc_XB_number_ptbr.gif | Bin 0 -> 449 bytes .../agc/images/vdc_XB_parkcustomerdial.gif | Bin 0 -> 896 bytes .../images/vdc_XB_parkcustomerdial_OFF.gif | Bin 0 -> 896 bytes .../images/vdc_XB_parkcustomerdial_OFF_es.gif | Bin 0 -> 661 bytes .../vdc_XB_parkcustomerdial_OFF_ptbr.gif | Bin 0 -> 916 bytes .../agc/images/vdc_XB_parkcustomerdial_es.gif | Bin 0 -> 659 bytes .../images/vdc_XB_parkcustomerdial_ptbr.gif | Bin 0 -> 916 bytes LANG_agc/agc/images/vdc_XB_seconds.gif | Bin 0 -> 352 bytes LANG_agc/agc/images/vdc_XB_seconds_es.gif | Bin 0 -> 333 bytes LANG_agc/agc/images/vdc_XB_seconds_ptbr.gif | Bin 0 -> 333 bytes LANG_agc/agc/images/vdc_tab_script.gif | Bin 0 -> 825 bytes LANG_agc/agc/images/vdc_tab_script_es.gif | Bin 0 -> 916 bytes LANG_agc/agc/images/vdc_tab_script_ptbr.gif | Bin 0 -> 825 bytes LANG_agc/agc/images/vdc_tab_vicidial.gif | Bin 0 -> 866 bytes LANG_agc/agc/images/vdc_tab_vicidial_ptbr.gif | Bin 0 -> 866 bytes LANG_agc/agc/inbound_popup.php | 348 + LANG_agc/agc/live_exten_check.php | 273 + LANG_agc/agc/manager_send.php | 903 +++ LANG_agc/agc/park_calls_display.php | 142 + LANG_agc/agc/vdc_db_query.php | 1512 ++++ LANG_agc/agc/vicidial.php | 5435 ++++++++++++++ LANG_agc/agc/voicemail_check.php | 136 + LANG_agc/agc_br/active_list_refresh.php | 463 ++ LANG_agc/agc_br/astguiclient.php | 2890 ++++++++ LANG_agc/agc_br/call_log_display.php | 192 + LANG_agc/agc_br/conf_exten_check.php | 258 + LANG_agc/agc_br/dbconnect.php | 15 + LANG_agc/agc_br/inbound_popup.php | 348 + LANG_agc/agc_br/live_exten_check.php | 273 + LANG_agc/agc_br/manager_send.php | 903 +++ LANG_agc/agc_br/park_calls_display.php | 142 + LANG_agc/agc_br/vdc_db_query.php | 1512 ++++ LANG_agc/agc_br/vicidial.php | 5435 ++++++++++++++ LANG_agc/agc_br/voicemail_check.php | 136 + LANG_agc/agc_de/active_list_refresh.php | 463 ++ LANG_agc/agc_de/astguiclient.php | 2890 ++++++++ LANG_agc/agc_de/call_log_display.php | 192 + LANG_agc/agc_de/conf_exten_check.php | 258 + LANG_agc/agc_de/dbconnect.php | 15 + LANG_agc/agc_de/inbound_popup.php | 348 + LANG_agc/agc_de/live_exten_check.php | 273 + LANG_agc/agc_de/manager_send.php | 903 +++ LANG_agc/agc_de/park_calls_display.php | 142 + LANG_agc/agc_de/vdc_db_query.php | 1512 ++++ LANG_agc/agc_de/vicidial.php | 5435 ++++++++++++++ LANG_agc/agc_de/voicemail_check.php | 136 + LANG_agc/agc_el/active_list_refresh.php | 463 ++ LANG_agc/agc_el/astguiclient.php | 2890 ++++++++ LANG_agc/agc_el/call_log_display.php | 192 + LANG_agc/agc_el/conf_exten_check.php | 258 + LANG_agc/agc_el/dbconnect.php | 15 + LANG_agc/agc_el/inbound_popup.php | 348 + LANG_agc/agc_el/live_exten_check.php | 273 + LANG_agc/agc_el/manager_send.php | 903 +++ LANG_agc/agc_el/park_calls_display.php | 142 + LANG_agc/agc_el/vdc_db_query.php | 1512 ++++ LANG_agc/agc_el/vicidial.php | 5435 ++++++++++++++ LANG_agc/agc_el/voicemail_check.php | 136 + LANG_agc/agc_en/active_list_refresh.php | 463 ++ LANG_agc/agc_en/astguiclient.php | 2890 ++++++++ LANG_agc/agc_en/call_log_display.php | 192 + LANG_agc/agc_en/conf_exten_check.php | 258 + LANG_agc/agc_en/dbconnect.php | 15 + LANG_agc/agc_en/inbound_popup.php | 348 + LANG_agc/agc_en/live_exten_check.php | 273 + LANG_agc/agc_en/manager_send.php | 903 +++ LANG_agc/agc_en/park_calls_display.php | 142 + LANG_agc/agc_en/vdc_db_query.php | 1512 ++++ LANG_agc/agc_en/vicidial.php | 5435 ++++++++++++++ LANG_agc/agc_en/voicemail_check.php | 136 + LANG_agc/agc_es/active_list_refresh.php | 463 ++ LANG_agc/agc_es/astguiclient.php | 2890 ++++++++ LANG_agc/agc_es/call_log_display.php | 192 + LANG_agc/agc_es/conf_exten_check.php | 258 + LANG_agc/agc_es/dbconnect.php | 15 + LANG_agc/agc_es/inbound_popup.php | 348 + LANG_agc/agc_es/live_exten_check.php | 273 + LANG_agc/agc_es/manager_send.php | 903 +++ LANG_agc/agc_es/park_calls_display.php | 142 + LANG_agc/agc_es/vdc_db_query.php | 1512 ++++ LANG_agc/agc_es/vicidial.php | 5435 ++++++++++++++ LANG_agc/agc_es/voicemail_check.php | 136 + LANG_agc/agc_fr/active_list_refresh.php | 463 ++ LANG_agc/agc_fr/astguiclient.php | 2890 ++++++++ LANG_agc/agc_fr/call_log_display.php | 192 + LANG_agc/agc_fr/conf_exten_check.php | 258 + LANG_agc/agc_fr/dbconnect.php | 15 + LANG_agc/agc_fr/inbound_popup.php | 348 + LANG_agc/agc_fr/live_exten_check.php | 273 + LANG_agc/agc_fr/manager_send.php | 903 +++ LANG_agc/agc_fr/park_calls_display.php | 142 + LANG_agc/agc_fr/vdc_db_query.php | 1512 ++++ LANG_agc/agc_fr/vicidial.php | 5435 ++++++++++++++ LANG_agc/agc_fr/voicemail_check.php | 136 + LANG_agc/agc_it/active_list_refresh.php | 463 ++ LANG_agc/agc_it/astguiclient.php | 2890 ++++++++ LANG_agc/agc_it/call_log_display.php | 192 + LANG_agc/agc_it/conf_exten_check.php | 258 + LANG_agc/agc_it/dbconnect.php | 15 + LANG_agc/agc_it/inbound_popup.php | 348 + LANG_agc/agc_it/live_exten_check.php | 273 + LANG_agc/agc_it/manager_send.php | 903 +++ LANG_agc/agc_it/park_calls_display.php | 142 + LANG_agc/agc_it/vdc_db_query.php | 1512 ++++ LANG_agc/agc_it/vicidial.php | 5435 ++++++++++++++ LANG_agc/agc_it/voicemail_check.php | 136 + LANG_agc/agc_pt/active_list_refresh.php | 463 ++ LANG_agc/agc_pt/astguiclient.php | 2890 ++++++++ LANG_agc/agc_pt/call_log_display.php | 192 + LANG_agc/agc_pt/conf_exten_check.php | 258 + LANG_agc/agc_pt/dbconnect.php | 15 + LANG_agc/agc_pt/inbound_popup.php | 348 + LANG_agc/agc_pt/live_exten_check.php | 273 + LANG_agc/agc_pt/manager_send.php | 903 +++ LANG_agc/agc_pt/park_calls_display.php | 142 + LANG_agc/agc_pt/vdc_db_query.php | 1512 ++++ LANG_agc/agc_pt/vicidial.php | 5435 ++++++++++++++ LANG_agc/agc_pt/voicemail_check.php | 136 + MySQL_AST_CREATE_tables.sql | 789 ++ VD_amd.agi | 368 + VD_amd_post.agi | 239 + VD_app_conference_0.6.zip | Bin 0 -> 234580 bytes VD_hangup.agi | 385 + VICIDIAL_IN_new_leads_file.pl | 867 +++ VICIDIAL_web/AST_CLOSERstats.php | 396 + VICIDIAL_web/AST_VDADstats.php | 417 ++ VICIDIAL_web/AST_VICIDIAL_hopperlist.php | 161 + VICIDIAL_web/AST_admin_log_display.php | 118 + VICIDIAL_web/AST_agent_performance.php | 232 + VICIDIAL_web/AST_agent_performance_detail.php | 406 + VICIDIAL_web/AST_agent_time_sheet.php | 281 + VICIDIAL_web/AST_agent_time_sheet_archive.php | 281 + VICIDIAL_web/AST_parkstats.php | 396 + VICIDIAL_web/AST_server_performance.php | 310 + VICIDIAL_web/AST_timeonVDAD.php | 255 + VICIDIAL_web/AST_timeonVDAD_closer.php | 316 + VICIDIAL_web/AST_timeonVDADall.php | 391 + VICIDIAL_web/AST_timeonVDADall_SIPmonitor.php | 395 + VICIDIAL_web/AST_timeoncall.php | 202 + VICIDIAL_web/AST_timeonpark.php | 219 + VICIDIAL_web/admin.php | 6514 +++++++++++++++++ VICIDIAL_web/admin_modify_lead.php | 476 ++ VICIDIAL_web/admin_search_lead.php | 224 + VICIDIAL_web/closer-fronter_popup.php | 515 ++ VICIDIAL_web/closer-fronter_popup2.php | 430 ++ VICIDIAL_web/closer.php | 353 + VICIDIAL_web/closer_dispo.php | 329 + VICIDIAL_web/closer_popup.php | 453 ++ VICIDIAL_web/count.htm | 1 + VICIDIAL_web/dbconnect.php | 20 + VICIDIAL_web/group_hourly_stats.php | 252 + VICIDIAL_web/help.gif | Bin 0 -> 492 bytes VICIDIAL_web/listloader.php | 698 ++ VICIDIAL_web/listloader.pl | 690 ++ VICIDIAL_web/listloaderMAIN.php | 79 + VICIDIAL_web/listloader_rowdisplay.pl | 62 + VICIDIAL_web/listloader_super.pl | 691 ++ VICIDIAL_web/log_test.php | 37 + VICIDIAL_web/new_listloader_superL.php | 1364 ++++ VICIDIAL_web/record_conf_1_hour.php | 156 + VICIDIAL_web/remote_dispo.php | 327 + VICIDIAL_web/server_stats.php | 96 + VICIDIAL_web/test.txt | 1 + VICIDIAL_web/user_stats.php | 316 + VICIDIAL_web/user_status.php | 238 + VICIDIAL_web/vdremote.php | 602 ++ agc/active_list_refresh.php | 482 ++ agc/astguiclient.php | 2899 ++++++++ agc/call_log_display.php | 196 + agc/conf_exten_check.php | 262 + agc/dbconnect.php | 18 + agc/images/agc_check_voicemail_BLINK.gif | Bin 0 -> 2627 bytes agc/images/agc_check_voicemail_BLINK_e.gif | Bin 0 -> 780 bytes agc/images/agc_check_voicemail_BLINK_es.gif | Bin 0 -> 780 bytes agc/images/agc_check_voicemail_BLINK_ptbr.gif | Bin 0 -> 886 bytes agc/images/agc_check_voicemail_OFF.gif | Bin 0 -> 919 bytes agc/images/agc_check_voicemail_OFF_es.gif | Bin 0 -> 785 bytes agc/images/agc_check_voicemail_OFF_ptbr.gif | Bin 0 -> 880 bytes agc/images/agc_check_voicemail_ON.gif | Bin 0 -> 919 bytes agc/images/agc_check_voicemail_ON_es.gif | Bin 0 -> 781 bytes agc/images/agc_check_voicemail_ON_ptbr.gif | Bin 0 -> 881 bytes agc/images/agc_live_call_OFF.gif | Bin 0 -> 541 bytes agc/images/agc_live_call_OFF_es.gif | Bin 0 -> 513 bytes agc/images/agc_live_call_OFF_ptbr.gif | Bin 0 -> 459 bytes agc/images/agc_live_call_ON.gif | Bin 0 -> 793 bytes agc/images/agc_live_call_ON_es.gif | Bin 0 -> 871 bytes agc/images/agc_live_call_ON_ptbr.gif | Bin 0 -> 2750 bytes agc/images/agc_tab_active_lines.gif | Bin 0 -> 886 bytes agc/images/agc_tab_active_lines_el.gif | Bin 0 -> 984 bytes agc/images/agc_tab_active_lines_es.gif | Bin 0 -> 704 bytes agc/images/agc_tab_active_lines_ptbr.gif | Bin 0 -> 1005 bytes agc/images/agc_tab_astguiclient.gif | Bin 0 -> 1092 bytes agc/images/agc_tab_astguiclient_ptbr.gif | Bin 0 -> 1092 bytes agc/images/agc_tab_conferences.gif | Bin 0 -> 928 bytes agc/images/agc_tab_conferences_el.gif | Bin 0 -> 861 bytes agc/images/agc_tab_conferences_es.gif | Bin 0 -> 718 bytes agc/images/agc_tab_conferences_ptbr.gif | Bin 0 -> 718 bytes agc/images/agc_tab_main.gif | Bin 0 -> 596 bytes agc/images/agc_tab_main_el.gif | Bin 0 -> 722 bytes agc/images/agc_tab_main_es.gif | Bin 0 -> 541 bytes agc/images/agc_tab_main_ptbr.gif | Bin 0 -> 541 bytes agc/images/blank.gif | Bin 0 -> 43 bytes agc/images/br.gif | Bin 0 -> 397 bytes agc/images/de.gif | Bin 0 -> 162 bytes agc/images/down.gif | Bin 0 -> 169 bytes agc/images/el.gif | Bin 0 -> 245 bytes agc/images/en.gif | Bin 0 -> 322 bytes agc/images/es.gif | Bin 0 -> 222 bytes agc/images/fr.gif | Bin 0 -> 217 bytes agc/images/it.gif | Bin 0 -> 198 bytes agc/images/pt.gif | Bin 0 -> 208 bytes agc/images/remove.gif | Bin 0 -> 176 bytes agc/images/up.gif | Bin 0 -> 169 bytes agc/images/vdc_LB_dialnextnumber.gif | Bin 0 -> 831 bytes agc/images/vdc_LB_dialnextnumber_OFF.gif | Bin 0 -> 827 bytes agc/images/vdc_LB_dialnextnumber_OFF_es.gif | Bin 0 -> 914 bytes agc/images/vdc_LB_dialnextnumber_OFF_ptbr.gif | Bin 0 -> 961 bytes agc/images/vdc_LB_dialnextnumber_es.gif | Bin 0 -> 914 bytes agc/images/vdc_LB_dialnextnumber_ptbr.gif | Bin 0 -> 965 bytes agc/images/vdc_LB_grabparkedcall.gif | Bin 0 -> 804 bytes agc/images/vdc_LB_grabparkedcall_OFF.gif | Bin 0 -> 802 bytes agc/images/vdc_LB_grabparkedcall_OFF_es.gif | Bin 0 -> 827 bytes agc/images/vdc_LB_grabparkedcall_OFF_ptbr.gif | Bin 0 -> 981 bytes agc/images/vdc_LB_grabparkedcall_es.gif | Bin 0 -> 826 bytes agc/images/vdc_LB_grabparkedcall_ptbr.gif | Bin 0 -> 985 bytes agc/images/vdc_LB_hangupcustomer.gif | Bin 0 -> 803 bytes agc/images/vdc_LB_hangupcustomer_OFF.gif | Bin 0 -> 803 bytes agc/images/vdc_LB_hangupcustomer_OFF_es.gif | Bin 0 -> 693 bytes agc/images/vdc_LB_hangupcustomer_OFF_ptbr.gif | Bin 0 -> 811 bytes agc/images/vdc_LB_hangupcustomer_es.gif | Bin 0 -> 697 bytes agc/images/vdc_LB_hangupcustomer_ptbr.gif | Bin 0 -> 1029 bytes agc/images/vdc_LB_parkcall.gif | Bin 0 -> 601 bytes agc/images/vdc_LB_parkcall_OFF.gif | Bin 0 -> 607 bytes agc/images/vdc_LB_parkcall_OFF_es.gif | Bin 0 -> 644 bytes agc/images/vdc_LB_parkcall_OFF_ptbr.gif | Bin 0 -> 830 bytes agc/images/vdc_LB_parkcall_es.gif | Bin 0 -> 646 bytes agc/images/vdc_LB_parkcall_ptbr.gif | Bin 0 -> 858 bytes agc/images/vdc_LB_pause.gif | Bin 0 -> 483 bytes agc/images/vdc_LB_pause_OFF.gif | Bin 0 -> 483 bytes agc/images/vdc_LB_pause_OFF_es.gif | Bin 0 -> 404 bytes agc/images/vdc_LB_pause_OFF_ptbr.gif | Bin 0 -> 438 bytes agc/images/vdc_LB_pause_es.gif | Bin 0 -> 410 bytes agc/images/vdc_LB_pause_ptbr.gif | Bin 0 -> 989 bytes agc/images/vdc_LB_resume.gif | Bin 0 -> 535 bytes agc/images/vdc_LB_resume_OFF.gif | Bin 0 -> 533 bytes agc/images/vdc_LB_resume_OFF_es.gif | Bin 0 -> 495 bytes agc/images/vdc_LB_resume_OFF_ptbr.gif | Bin 0 -> 416 bytes agc/images/vdc_LB_resume_es.gif | Bin 0 -> 500 bytes agc/images/vdc_LB_resume_ptbr.gif | Bin 0 -> 394 bytes agc/images/vdc_LB_senddtmf.gif | Bin 0 -> 567 bytes agc/images/vdc_LB_senddtmf_OFF.gif | Bin 0 -> 563 bytes agc/images/vdc_LB_senddtmf_OFF_es.gif | Bin 0 -> 563 bytes agc/images/vdc_LB_senddtmf_OFF_ptbr.gif | Bin 0 -> 563 bytes agc/images/vdc_LB_senddtmf_es.gif | Bin 0 -> 564 bytes agc/images/vdc_LB_senddtmf_ptbr.gif | Bin 0 -> 564 bytes agc/images/vdc_LB_spacer.gif | Bin 0 -> 90 bytes agc/images/vdc_LB_startrecording.gif | Bin 0 -> 778 bytes agc/images/vdc_LB_startrecording_OFF.gif | Bin 0 -> 778 bytes agc/images/vdc_LB_startrecording_OFF_es.gif | Bin 0 -> 788 bytes agc/images/vdc_LB_startrecording_OFF_ptbr.gif | Bin 0 -> 783 bytes agc/images/vdc_LB_startrecording_es.gif | Bin 0 -> 788 bytes agc/images/vdc_LB_startrecording_ptbr.gif | Bin 0 -> 784 bytes agc/images/vdc_LB_stoprecording.gif | Bin 0 -> 758 bytes agc/images/vdc_LB_stoprecording_OFF.gif | Bin 0 -> 757 bytes agc/images/vdc_LB_stoprecording_OFF_es.gif | Bin 0 -> 701 bytes agc/images/vdc_LB_stoprecording_OFF_ptbr.gif | Bin 0 -> 778 bytes agc/images/vdc_LB_stoprecording_es.gif | Bin 0 -> 699 bytes agc/images/vdc_LB_stoprecording_ptbr.gif | Bin 0 -> 779 bytes agc/images/vdc_LB_transferconf.gif | Bin 0 -> 732 bytes agc/images/vdc_LB_transferconf_OFF.gif | Bin 0 -> 732 bytes agc/images/vdc_LB_transferconf_OFF_es.gif | Bin 0 -> 712 bytes agc/images/vdc_LB_transferconf_OFF_ptbr.gif | Bin 0 -> 896 bytes agc/images/vdc_LB_transferconf_es.gif | Bin 0 -> 714 bytes agc/images/vdc_LB_transferconf_ptbr.gif | Bin 0 -> 898 bytes agc/images/vdc_LB_webform.gif | Bin 0 -> 542 bytes agc/images/vdc_LB_webform_OFF.gif | Bin 0 -> 615 bytes agc/images/vdc_LB_webform_OFF_es.gif | Bin 0 -> 661 bytes agc/images/vdc_LB_webform_OFF_ptbr.gif | Bin 0 -> 661 bytes agc/images/vdc_LB_webform_es.gif | Bin 0 -> 583 bytes agc/images/vdc_LB_webform_ptbr.gif | Bin 0 -> 583 bytes agc/images/vdc_XB_ammessage.gif | Bin 0 -> 396 bytes agc/images/vdc_XB_ammessage_OFF.gif | Bin 0 -> 403 bytes agc/images/vdc_XB_blindtransfer.gif | Bin 0 -> 774 bytes agc/images/vdc_XB_blindtransfer_OFF.gif | Bin 0 -> 774 bytes agc/images/vdc_XB_blindtransfer_OFF_es.gif | Bin 0 -> 758 bytes agc/images/vdc_XB_blindtransfer_OFF_ptbr.gif | Bin 0 -> 901 bytes agc/images/vdc_XB_blindtransfer_es.gif | Bin 0 -> 758 bytes agc/images/vdc_XB_blindtransfer_ptbr.gif | Bin 0 -> 901 bytes agc/images/vdc_XB_channel.gif | Bin 0 -> 314 bytes agc/images/vdc_XB_channel_es.gif | Bin 0 -> 242 bytes agc/images/vdc_XB_channel_ptbr.gif | Bin 0 -> 242 bytes agc/images/vdc_XB_code.gif | Bin 0 -> 247 bytes agc/images/vdc_XB_dialwithcustomer.gif | Bin 0 -> 881 bytes agc/images/vdc_XB_dialwithcustomer_OFF.gif | Bin 0 -> 881 bytes agc/images/vdc_XB_dialwithcustomer_OFF_es.gif | Bin 0 -> 776 bytes .../vdc_XB_dialwithcustomer_OFF_ptbr.gif | Bin 0 -> 873 bytes agc/images/vdc_XB_dialwithcustomer_es.gif | Bin 0 -> 776 bytes agc/images/vdc_XB_dialwithcustomer_ptbr.gif | Bin 0 -> 873 bytes agc/images/vdc_XB_hangupbothlines.gif | Bin 0 -> 849 bytes agc/images/vdc_XB_hangupbothlines_OFF.gif | Bin 0 -> 849 bytes agc/images/vdc_XB_hangupbothlines_OFF_es.gif | Bin 0 -> 809 bytes .../vdc_XB_hangupbothlines_OFF_ptbr.gif | Bin 0 -> 858 bytes agc/images/vdc_XB_hangupbothlines_es.gif | Bin 0 -> 809 bytes agc/images/vdc_XB_hangupbothlines_ptbr.gif | Bin 0 -> 858 bytes agc/images/vdc_XB_hangupxferline.gif | Bin 0 -> 803 bytes agc/images/vdc_XB_hangupxferline_OFF.gif | Bin 0 -> 803 bytes agc/images/vdc_XB_hangupxferline_OFF_es.gif | Bin 0 -> 702 bytes agc/images/vdc_XB_hangupxferline_OFF_ptbr.gif | Bin 0 -> 828 bytes agc/images/vdc_XB_hangupxferline_es.gif | Bin 0 -> 702 bytes agc/images/vdc_XB_hangupxferline_ptbr.gif | Bin 0 -> 828 bytes agc/images/vdc_XB_header.gif | Bin 0 -> 884 bytes agc/images/vdc_XB_header_es.gif | Bin 0 -> 639 bytes agc/images/vdc_XB_header_ptbr.gif | Bin 0 -> 639 bytes agc/images/vdc_XB_hotkeysactive.gif | Bin 0 -> 791 bytes agc/images/vdc_XB_hotkeysactive_OFF.gif | Bin 0 -> 786 bytes .../vdc_XB_hotkeysactive_OFF_es-orig.gif | Bin 0 -> 1231 bytes agc/images/vdc_XB_hotkeysactive_OFF_es.gif | Bin 0 -> 1256 bytes agc/images/vdc_XB_hotkeysactive_OFF_ptbr.gif | Bin 0 -> 948 bytes agc/images/vdc_XB_hotkeysactive_es.gif | Bin 0 -> 1231 bytes agc/images/vdc_XB_hotkeysactive_ptbr.gif | Bin 0 -> 997 bytes agc/images/vdc_XB_hotkeysinactive_es.gif | Bin 0 -> 1256 bytes agc/images/vdc_XB_internalcloser.gif | Bin 0 -> 801 bytes agc/images/vdc_XB_internalcloser_OFF.gif | Bin 0 -> 801 bytes agc/images/vdc_XB_internalcloser_OFF_es.gif | Bin 0 -> 640 bytes agc/images/vdc_XB_internalcloser_OFF_ptbr.gif | Bin 0 -> 640 bytes agc/images/vdc_XB_internalcloser_es.gif | Bin 0 -> 640 bytes agc/images/vdc_XB_internalcloser_ptbr.gif | Bin 0 -> 640 bytes agc/images/vdc_XB_leave3waycall.gif | Bin 0 -> 816 bytes agc/images/vdc_XB_leave3waycall_OFF.gif | Bin 0 -> 816 bytes agc/images/vdc_XB_leave3waycall_OFF_es.gif | Bin 0 -> 834 bytes agc/images/vdc_XB_leave3waycall_OFF_ptbr.gif | Bin 0 -> 816 bytes agc/images/vdc_XB_leave3waycall_es.gif | Bin 0 -> 834 bytes agc/images/vdc_XB_leave3waycall_ptbr.gif | Bin 0 -> 816 bytes agc/images/vdc_XB_localcloser.gif | Bin 0 -> 728 bytes agc/images/vdc_XB_localcloser_OFF.gif | Bin 0 -> 728 bytes agc/images/vdc_XB_localcloser_OFF_es.gif | Bin 0 -> 607 bytes agc/images/vdc_XB_localcloser_OFF_ptbr.gif | Bin 0 -> 607 bytes agc/images/vdc_XB_localcloser_es.gif | Bin 0 -> 606 bytes agc/images/vdc_XB_localcloser_ptbr.gif | Bin 0 -> 606 bytes agc/images/vdc_XB_number.gif | Bin 0 -> 480 bytes agc/images/vdc_XB_number_es.gif | Bin 0 -> 416 bytes agc/images/vdc_XB_number_ptbr.gif | Bin 0 -> 449 bytes agc/images/vdc_XB_parkcustomerdial.gif | Bin 0 -> 896 bytes agc/images/vdc_XB_parkcustomerdial_OFF.gif | Bin 0 -> 896 bytes agc/images/vdc_XB_parkcustomerdial_OFF_es.gif | Bin 0 -> 661 bytes .../vdc_XB_parkcustomerdial_OFF_ptbr.gif | Bin 0 -> 916 bytes agc/images/vdc_XB_parkcustomerdial_es.gif | Bin 0 -> 659 bytes agc/images/vdc_XB_parkcustomerdial_ptbr.gif | Bin 0 -> 916 bytes agc/images/vdc_XB_seconds.gif | Bin 0 -> 352 bytes agc/images/vdc_XB_seconds_es.gif | Bin 0 -> 333 bytes agc/images/vdc_XB_seconds_ptbr.gif | Bin 0 -> 333 bytes agc/images/vdc_tab_script.gif | Bin 0 -> 825 bytes agc/images/vdc_tab_script_es.gif | Bin 0 -> 916 bytes agc/images/vdc_tab_script_ptbr.gif | Bin 0 -> 825 bytes agc/images/vdc_tab_vicidial.gif | Bin 0 -> 866 bytes agc/images/vdc_tab_vicidial_ptbr.gif | Bin 0 -> 866 bytes agc/inbound_popup.php | 351 + agc/live_exten_check.php | 277 + agc/manager_send.php | 908 +++ agc/park_calls_display.php | 146 + agc/vdc_db_query.php | 1512 ++++ agc/vicidial.php | 5435 ++++++++++++++ agc/voicemail_check.php | 140 + agi-CIDtest.agi | 175 + agi-VDAD_LB_closer.agi | 557 ++ agi-VDAD_LB_closer_inbound.agi | 680 ++ agi-VDAD_LB_transfer.agi | 532 ++ agi-VDAD_LO_closer.agi | 642 ++ agi-VDAD_LO_closer_inbound.agi | 770 ++ agi-VDAD_LO_transfer.agi | 606 ++ agi-VDADautoREMINDER.agi | 610 ++ agi-VDADautoREMINDERxfer.agi | 673 ++ agi-VDADcloser.agi | 532 ++ agi-VDADcloser_PHONE.agi | 566 ++ agi-VDADcloser_inbound.agi | 664 ++ agi-VDADcloser_inboundANI.agi | 642 ++ agi-VDADcloser_inboundCID-debug.agi | 665 ++ agi-VDADcloser_inboundCID.agi | 658 ++ agi-VDADcloser_inboundCIDlookup.agi | 671 ++ agi-VDADcloser_inbound_5ID.agi | 664 ++ agi-VDADcloser_inbound_NOCID.agi | 591 ++ agi-VDADlisten_DTMF.agi | 191 + agi-VDADtransfer.agi | 501 ++ agi-VDADtransferSURVEY.agi | 651 ++ agi-dtmf.agi | 98 + agi-record_prompts.agi | 406 + app_conference/0.gsm | Bin 0 -> 429 bytes app_conference/0.wav | Bin 0 -> 4100 bytes app_conference/1.gsm | 1 + app_conference/1.wav | Bin 0 -> 4100 bytes app_conference/2.gsm | 3 + app_conference/2.wav | Bin 0 -> 4018 bytes app_conference/3.gsm | 2 + app_conference/3.wav | Bin 0 -> 4046 bytes app_conference/4.gsm | 2 + app_conference/4.wav | Bin 0 -> 3990 bytes app_conference/5.gsm | 1 + app_conference/5.wav | Bin 0 -> 3990 bytes app_conference/6.gsm | 1 + app_conference/6.wav | Bin 0 -> 4046 bytes app_conference/64_Makefile | 115 + app_conference/7.gsm | 2 + app_conference/7.wav | Bin 0 -> 4072 bytes app_conference/8.gsm | Bin 0 -> 429 bytes app_conference/8.wav | Bin 0 -> 4018 bytes app_conference/9.gsm | Bin 0 -> 429 bytes app_conference/9.wav | Bin 0 -> 4018 bytes app_conference/LICENSE | 341 + app_conference/Makefile | 121 + app_conference/README | 170 + app_conference/VICIDIAL.txt | 86 + app_conference/app_conference.c | 146 + app_conference/app_conference.h | 200 + app_conference/cli.c | 332 + app_conference/cli.h | 47 + app_conference/common.h | 50 + app_conference/conf_frame.h | 61 + app_conference/conference.c | 1410 ++++ app_conference/conference.h | 121 + app_conference/enter.gsm | Bin 0 -> 231 bytes app_conference/frame.c | 614 ++ app_conference/frame.h | 60 + app_conference/hash.gsm | 2 + app_conference/hash.wav | Bin 0 -> 3990 bytes app_conference/leave.gsm | Bin 0 -> 330 bytes app_conference/libspeex/CVS/Entries | 7 + app_conference/libspeex/CVS/Repository | 1 + app_conference/libspeex/CVS/Root | 1 + app_conference/libspeex/misc.c | 145 + app_conference/libspeex/misc.h | 147 + app_conference/libspeex/preprocess.c | 1136 +++ app_conference/libspeex/qc_20060323.zip | Bin 0 -> 22409 bytes app_conference/libspeex/smallft.c | 1256 ++++ app_conference/libspeex/smallft.h | 42 + app_conference/libspeex/speex_preprocess.h | 139 + app_conference/member.c | 1946 +++++ app_conference/member.h | 212 + app_conference/star.gsm | 2 + app_conference/star.wav | Bin 0 -> 4124 bytes astLEADLOADER.pl | 1654 +++++ astguiclient_web/AST_inboundEXTstats.php | 400 + astguiclient_web/admin.php | 1824 +++++ astguiclient_web/dbconnect.php | 14 + astguiclient_web/help.gif | Bin 0 -> 492 bytes astguiclient_web/inbound_popup.php | 228 + astguiclient_web/phone_stats.php | 244 + astguiclient_web/remote_inbound.php | 169 + astguiclient_web/test.php | 30 + call_inbound.agi | 235 + call_log.agi | 326 + call_logCID.agi | 309 + call_park.agi | 224 + call_park_EXT.agi | 223 + call_park_I.agi | 230 + call_park_L.agi | 307 + call_park_W.agi | 307 + debug_speak.agi | 123 + docs/ACQS.txt | 94 + docs/APP_CONFERENCE.txt | 86 + docs/CALLBACKS_PROCESS.txt | 98 + docs/CONF_Asterisk.txt | 9 + docs/CONF_MySQL.txt | 17 + docs/CONF_VICIDIAL_MySQL.txt | 12 + docs/LICENSE.txt | 278 + docs/LOAD_BALANCING.txt | 123 + docs/README.txt | 713 ++ docs/REQUIREMENTS.txt | 32 + docs/SCRATCH_INSTALL.txt | 2609 +++++++ docs/TODO.txt | 116 + docs/TODO_1.1.11.txt | 208 + docs/TODO_1.1.12.txt | 489 ++ docs/VICIDIAL.txt | 185 + install_server_files.pl | 510 ++ invalid_speak.agi | 139 + libs/AST_VICI_conf.pl.bak | 146 + libs/AUS_zipcode_ranges.txt | 14 + libs/Asterisk.pm | 20 + libs/Asterisk/AGI.pm | 685 ++ libs/Asterisk/DONOTUSE_AST_VICI_conf.pl | 146 + libs/Asterisk/Manager.pm | 412 ++ libs/Asterisk/Outgoing.pm | 110 + libs/Asterisk/QCall.pm | 61 + libs/Asterisk/Voicemail.pm | 261 + libs/Asterisk/buttons.gif | Bin 0 -> 10160 bytes libs/Asterisk/vm_indicator_anim.gif | Bin 0 -> 311 bytes libs/Asterisk/voicemail_digits.gif | Bin 0 -> 1812 bytes libs/Asterisk/voicemail_new.gif | Bin 0 -> 240 bytes libs/Asterisk/voicemail_old.gif | Bin 0 -> 230 bytes libs/Asterisk/voicemail_up.gif | Bin 0 -> 520 bytes libs/MySQL.pm | 1015 +++ libs/Net/HTTP.pm | 266 + libs/Net/HTTP/Methods.pm | 520 ++ libs/Net/HTTP/NB.pm | 106 + libs/Net/HTTPS.pm | 55 + libs/Net/MySQL.pm | 1015 +++ libs/Net/SSH.pm | 255 + libs/Net/Telnet.pm | 5252 +++++++++++++ libs/Telnet.pm | 5252 +++++++++++++ libs/Time/HiRes.1.59.pm | 359 + libs/Time/HiRes.1.65.pm | 369 + libs/Time/HiRes.pm | 351 + libs/Time/Local.pm | 289 + libs/Time/Other_HiRes_versions/HiRes.1.55.pm | 351 + libs/Time/Other_HiRes_versions/HiRes.1.59.pm | 359 + libs/Time/Other_HiRes_versions/HiRes.1.65.pm | 369 + libs/Time/Other_HiRes_versions/HiRes.pm | 359 + libs/Time/gmtime.pm | 90 + libs/Time/localtime.pm | 86 + libs/Time/tm.pm | 33 + libs/US_zipcode_ranges.txt | 51 + newt-0.51.6.tar.gz | Bin 0 -> 150759 bytes park_CID.agi | 164 + phone_codes_GMT.txt | 1011 +++ sphinxNA.zip | Bin 0 -> 27727 bytes start_asterisk_boot.pl | 14 + testMULTI_VICIDIAL_lead_file.csv | 13 + testMULTI_VICIDIAL_lead_file.txt | 13 + testMULTI_VICIDIAL_lead_file.xls | Bin 0 -> 16896 bytes test_VICIDIAL_lead_file.txt | 13 + translations/br_language.txt | 401 + translations/de_language.txt | 403 + translations/de_language_admin.txt | 1059 +++ translations/el_language.txt | 401 + translations/el_language_admin.txt | 1066 +++ translations/es_language.txt | 403 + translations/es_language_admin.txt | 1067 +++ translations/fr_language.txt | 403 + translations/it_language.txt | 403 + translations/pt_language.txt | 403 + .../TO_BE_TRANSLATED_admin_1.1.12_de.txt | 116 + .../raw_translation_files/language.txt | 402 + .../raw_translation_files/language_admin.txt | 936 +++ .../raw_translation_files/languages.txt_en_de | 8 + .../raw_translation_files/languages.txt_en_el | 216 + .../raw_translation_files/languages.txt_en_es | 127 + .../raw_translation_files/languages.txt_en_fr | 10 + .../raw_translation_files/languages.txt_en_it | 10 + .../raw_translation_files/languages.txt_en_pt | 10 + 992 files changed, 317439 insertions(+) create mode 100644 ADMIN_adjust_GMTnow_on_leads.pl create mode 100644 ADMIN_area_code_populate.pl create mode 100644 ADMIN_keepalive_AST_VDautodial.pl create mode 100644 ADMIN_keepalive_AST_VDremote_agents.pl create mode 100644 ADMIN_keepalive_AST_send_listen.pl create mode 100644 ADMIN_keepalive_AST_update.pl create mode 100644 ADMIN_keepalive_send_listen.at create mode 100644 ADMIN_restart_roll_logs.pl create mode 100644 AST_CRON_mix_recordings.pl create mode 100644 AST_CRON_mix_recordings_BASIC.pl create mode 100644 AST_CRON_mix_recordings_GSM.pl create mode 100644 AST_CRON_mix_recordings_MP3.pl create mode 100644 AST_DB_optimize.pl create mode 100644 AST_SERVER_conf.pl create mode 100644 AST_VDauto_dial.pl create mode 100644 AST_VDhopper.pl create mode 100644 AST_VDremote_agents.pl create mode 100644 AST_agent_week.pl create mode 100644 AST_cleanup_agent_log.pl create mode 100644 AST_conf_update.pl create mode 100644 AST_flush_DBqueue.pl create mode 100644 AST_manager_kill_hung_congested.pl create mode 100644 AST_manager_listen.pl create mode 100644 AST_manager_send.pl create mode 100644 AST_reset_mysql_vars.pl create mode 100644 AST_send_action_child.pl create mode 100644 AST_update.pl create mode 100644 AST_vm_update.pl create mode 100644 DBI-scripts/AST_VDhopper.pl create mode 100644 DBI-scripts/AST_agent_week.pl create mode 100644 DTMF_sounds/0.gsm create mode 100644 DTMF_sounds/0.wav create mode 100644 DTMF_sounds/1.gsm create mode 100644 DTMF_sounds/1.wav create mode 100644 DTMF_sounds/2.gsm create mode 100644 DTMF_sounds/2.wav create mode 100644 DTMF_sounds/3.gsm create mode 100644 DTMF_sounds/3.wav create mode 100644 DTMF_sounds/4.gsm create mode 100644 DTMF_sounds/4.wav create mode 100644 DTMF_sounds/5.gsm create mode 100644 DTMF_sounds/5.wav create mode 100644 DTMF_sounds/6.gsm create mode 100644 DTMF_sounds/6.wav create mode 100644 DTMF_sounds/7.gsm create mode 100644 DTMF_sounds/7.wav create mode 100644 DTMF_sounds/8.gsm create mode 100644 DTMF_sounds/8.wav create mode 100644 DTMF_sounds/9.gsm create mode 100644 DTMF_sounds/9.wav create mode 100644 DTMF_sounds/US_pol_survey_hello.gsm create mode 100644 DTMF_sounds/US_pol_survey_transfer.gsm create mode 100644 DTMF_sounds/US_reminder_callback.gsm create mode 100644 DTMF_sounds/US_reminder_goodbye.gsm create mode 100644 DTMF_sounds/US_reminder_message.gsm create mode 100644 DTMF_sounds/US_reminder_options.gsm create mode 100644 DTMF_sounds/US_thanks_no_contact.gsm create mode 100644 DTMF_sounds/auth-thankyou.gsm create mode 100644 DTMF_sounds/buzz.gsm create mode 100644 DTMF_sounds/ding.gsm create mode 100644 DTMF_sounds/enter.gsm create mode 100644 DTMF_sounds/four_digit_id.gsm create mode 100644 DTMF_sounds/generic_hold.gsm create mode 100644 DTMF_sounds/hash.gsm create mode 100644 DTMF_sounds/hash.wav create mode 100644 DTMF_sounds/hold_tone.gsm create mode 100644 DTMF_sounds/ld_invalid_pin_number.gsm create mode 100644 DTMF_sounds/ld_welcome_pin_number.gsm create mode 100644 DTMF_sounds/leave.gsm create mode 100644 DTMF_sounds/silence.wav create mode 100644 DTMF_sounds/star.gsm create mode 100644 DTMF_sounds/star.wav create mode 100644 DTMF_sounds/vm-goodbye.gsm create mode 100644 DTMF_sounds/vm-msgsaved.gsm create mode 100644 DTMF_sounds/vm-rec-generic.gsm create mode 100644 DTMF_sounds/vm-review.gsm create mode 100644 LANG_admin.zip create mode 100644 LANG_admin/astguiclient/AST_inboundEXTstats.php create mode 100644 LANG_admin/astguiclient/admin.php create mode 100644 LANG_admin/astguiclient/dbconnect.php create mode 100644 LANG_admin/astguiclient/help.gif create mode 100644 LANG_admin/astguiclient/inbound_popup.php create mode 100644 LANG_admin/astguiclient/phone_stats.php create mode 100644 LANG_admin/astguiclient/remote_inbound.php create mode 100644 LANG_admin/astguiclient/test.php create mode 100644 LANG_admin/astguiclient_de/AST_inboundEXTstats.php create mode 100644 LANG_admin/astguiclient_de/admin.php create mode 100644 LANG_admin/astguiclient_de/dbconnect.php create mode 100644 LANG_admin/astguiclient_de/help.gif create mode 100644 LANG_admin/astguiclient_de/inbound_popup.php create mode 100644 LANG_admin/astguiclient_de/phone_stats.php create mode 100644 LANG_admin/astguiclient_de/remote_inbound.php create mode 100644 LANG_admin/astguiclient_el/AST_inboundEXTstats.php create mode 100644 LANG_admin/astguiclient_el/admin.php create mode 100644 LANG_admin/astguiclient_el/dbconnect.php create mode 100644 LANG_admin/astguiclient_el/help.gif create mode 100644 LANG_admin/astguiclient_el/inbound_popup.php create mode 100644 LANG_admin/astguiclient_el/phone_stats.php create mode 100644 LANG_admin/astguiclient_el/remote_inbound.php create mode 100644 LANG_admin/astguiclient_en/AST_inboundEXTstats.php create mode 100644 LANG_admin/astguiclient_en/admin.php create mode 100644 LANG_admin/astguiclient_en/dbconnect.php create mode 100644 LANG_admin/astguiclient_en/help.gif create mode 100644 LANG_admin/astguiclient_en/inbound_popup.php create mode 100644 LANG_admin/astguiclient_en/phone_stats.php create mode 100644 LANG_admin/astguiclient_en/remote_inbound.php create mode 100644 LANG_admin/astguiclient_es/AST_inboundEXTstats.php create mode 100644 LANG_admin/astguiclient_es/admin.php create mode 100644 LANG_admin/astguiclient_es/dbconnect.php create mode 100644 LANG_admin/astguiclient_es/help.gif create mode 100644 LANG_admin/astguiclient_es/inbound_popup.php create mode 100644 LANG_admin/astguiclient_es/phone_stats.php create mode 100644 LANG_admin/astguiclient_es/remote_inbound.php create mode 100644 LANG_admin/vicidial/AST_CLOSERstats.php create mode 100644 LANG_admin/vicidial/AST_VDADstats.php create mode 100644 LANG_admin/vicidial/AST_VICIDIAL_hopperlist.php create mode 100644 LANG_admin/vicidial/AST_admin_log_display.php create mode 100644 LANG_admin/vicidial/AST_agent_performance.php create mode 100644 LANG_admin/vicidial/AST_agent_performance_detail.php create mode 100644 LANG_admin/vicidial/AST_agent_time_sheet.php create mode 100644 LANG_admin/vicidial/AST_agent_time_sheet_archive.php create mode 100644 LANG_admin/vicidial/AST_parkstats.php create mode 100644 LANG_admin/vicidial/AST_server_performance.php create mode 100644 LANG_admin/vicidial/AST_timeonVDAD.php create mode 100644 LANG_admin/vicidial/AST_timeonVDAD_closer.php create mode 100644 LANG_admin/vicidial/AST_timeonVDADall.php create mode 100644 LANG_admin/vicidial/AST_timeonVDADall_SIPmonitor.php create mode 100644 LANG_admin/vicidial/AST_timeoncall.php create mode 100644 LANG_admin/vicidial/AST_timeonpark.php create mode 100644 LANG_admin/vicidial/admin-old.php create mode 100644 LANG_admin/vicidial/admin.php create mode 100644 LANG_admin/vicidial/admin_modify_lead.php create mode 100644 LANG_admin/vicidial/admin_search_lead.php create mode 100644 LANG_admin/vicidial/closer-fronter_popup.php create mode 100644 LANG_admin/vicidial/closer-fronter_popup2.php create mode 100644 LANG_admin/vicidial/closer.php create mode 100644 LANG_admin/vicidial/closer_dispo.php create mode 100644 LANG_admin/vicidial/closer_popup.php create mode 100644 LANG_admin/vicidial/count.htm create mode 100644 LANG_admin/vicidial/dbconnect.php create mode 100644 LANG_admin/vicidial/group_hourly_stats.php create mode 100644 LANG_admin/vicidial/help.gif create mode 100644 LANG_admin/vicidial/listloader.php create mode 100644 LANG_admin/vicidial/listloader.pl create mode 100644 LANG_admin/vicidial/listloaderMAIN.php create mode 100644 LANG_admin/vicidial/listloader_rowdisplay.pl create mode 100644 LANG_admin/vicidial/listloader_super.pl create mode 100644 LANG_admin/vicidial/log_test.php create mode 100644 LANG_admin/vicidial/new_listloader_superL.php create mode 100644 LANG_admin/vicidial/record_conf_1_hour.php create mode 100644 LANG_admin/vicidial/remote_dispo.php create mode 100644 LANG_admin/vicidial/server_stats.php create mode 100644 LANG_admin/vicidial/test.txt create mode 100644 LANG_admin/vicidial/user_stats.php create mode 100644 LANG_admin/vicidial/user_status.php create mode 100644 LANG_admin/vicidial/vdremote.php create mode 100644 LANG_admin/vicidial_de/AST_CLOSERstats.php create mode 100644 LANG_admin/vicidial_de/AST_VDADstats.php create mode 100644 LANG_admin/vicidial_de/AST_VICIDIAL_hopperlist.php create mode 100644 LANG_admin/vicidial_de/AST_admin_log_display.php create mode 100644 LANG_admin/vicidial_de/AST_agent_performance.php create mode 100644 LANG_admin/vicidial_de/AST_agent_performance_detail.php create mode 100644 LANG_admin/vicidial_de/AST_agent_time_sheet.php create mode 100644 LANG_admin/vicidial_de/AST_server_performance.php create mode 100644 LANG_admin/vicidial_de/AST_timeonVDAD.php create mode 100644 LANG_admin/vicidial_de/AST_timeonVDAD_closer.php create mode 100644 LANG_admin/vicidial_de/AST_timeonVDADall.php create mode 100644 LANG_admin/vicidial_de/AST_timeonVDADall_SIPmonitor.php create mode 100644 LANG_admin/vicidial_de/AST_timeoncall.php create mode 100644 LANG_admin/vicidial_de/AST_timeonpark.php create mode 100644 LANG_admin/vicidial_de/admin.php create mode 100644 LANG_admin/vicidial_de/admin_modify_lead.php create mode 100644 LANG_admin/vicidial_de/admin_search_lead.php create mode 100644 LANG_admin/vicidial_de/count.htm create mode 100644 LANG_admin/vicidial_de/dbconnect.php create mode 100644 LANG_admin/vicidial_de/group_hourly_stats.php create mode 100644 LANG_admin/vicidial_de/help.gif create mode 100644 LANG_admin/vicidial_de/listloader.php create mode 100644 LANG_admin/vicidial_de/listloaderMAIN.php create mode 100644 LANG_admin/vicidial_de/new_listloader_superL.php create mode 100644 LANG_admin/vicidial_de/remote_dispo.php create mode 100644 LANG_admin/vicidial_de/server_stats.php create mode 100644 LANG_admin/vicidial_de/user_stats.php create mode 100644 LANG_admin/vicidial_de/user_status.php create mode 100644 LANG_admin/vicidial_de/vdremote.php create mode 100644 LANG_admin/vicidial_el/AST_CLOSERstats.php create mode 100644 LANG_admin/vicidial_el/AST_VDADstats.php create mode 100644 LANG_admin/vicidial_el/AST_VICIDIAL_hopperlist.php create mode 100644 LANG_admin/vicidial_el/AST_admin_log_display.php create mode 100644 LANG_admin/vicidial_el/AST_agent_performance.php create mode 100644 LANG_admin/vicidial_el/AST_agent_performance_detail.php create mode 100644 LANG_admin/vicidial_el/AST_agent_time_sheet.php create mode 100644 LANG_admin/vicidial_el/AST_server_performance.php create mode 100644 LANG_admin/vicidial_el/AST_timeonVDAD.php create mode 100644 LANG_admin/vicidial_el/AST_timeonVDAD_closer.php create mode 100644 LANG_admin/vicidial_el/AST_timeonVDADall.php create mode 100644 LANG_admin/vicidial_el/AST_timeonVDADall_SIPmonitor.php create mode 100644 LANG_admin/vicidial_el/AST_timeoncall.php create mode 100644 LANG_admin/vicidial_el/AST_timeonpark.php create mode 100644 LANG_admin/vicidial_el/admin.php create mode 100644 LANG_admin/vicidial_el/admin_modify_lead.php create mode 100644 LANG_admin/vicidial_el/admin_search_lead.php create mode 100644 LANG_admin/vicidial_el/count.htm create mode 100644 LANG_admin/vicidial_el/dbconnect.php create mode 100644 LANG_admin/vicidial_el/group_hourly_stats.php create mode 100644 LANG_admin/vicidial_el/help.gif create mode 100644 LANG_admin/vicidial_el/htglobalize.php create mode 100644 LANG_admin/vicidial_el/listloader.php create mode 100644 LANG_admin/vicidial_el/listloaderMAIN.php create mode 100644 LANG_admin/vicidial_el/listloader_stmts.txt create mode 100644 LANG_admin/vicidial_el/new_listloader_superL.php create mode 100644 LANG_admin/vicidial_el/project_auth_entries.txt create mode 100644 LANG_admin/vicidial_el/remote_dispo.php create mode 100644 LANG_admin/vicidial_el/server_stats.php create mode 100644 LANG_admin/vicidial_el/user_stats.php create mode 100644 LANG_admin/vicidial_el/user_status.php create mode 100644 LANG_admin/vicidial_el/vdremote.php create mode 100644 LANG_admin/vicidial_en/AST_CLOSERstats.php create mode 100644 LANG_admin/vicidial_en/AST_VDADstats.php create mode 100644 LANG_admin/vicidial_en/AST_VICIDIAL_hopperlist.php create mode 100644 LANG_admin/vicidial_en/AST_admin_log_display.php create mode 100644 LANG_admin/vicidial_en/AST_agent_performance.php create mode 100644 LANG_admin/vicidial_en/AST_agent_performance_detail.php create mode 100644 LANG_admin/vicidial_en/AST_agent_time_sheet.php create mode 100644 LANG_admin/vicidial_en/AST_server_performance.php create mode 100644 LANG_admin/vicidial_en/AST_timeonVDAD.php create mode 100644 LANG_admin/vicidial_en/AST_timeonVDAD_closer.php create mode 100644 LANG_admin/vicidial_en/AST_timeonVDADall.php create mode 100644 LANG_admin/vicidial_en/AST_timeonVDADall_SIPmonitor.php create mode 100644 LANG_admin/vicidial_en/AST_timeoncall.php create mode 100644 LANG_admin/vicidial_en/AST_timeonpark.php create mode 100644 LANG_admin/vicidial_en/admin.php create mode 100644 LANG_admin/vicidial_en/admin_changes_log.txt create mode 100644 LANG_admin/vicidial_en/admin_modify_lead.php create mode 100644 LANG_admin/vicidial_en/admin_search_lead.php create mode 100644 LANG_admin/vicidial_en/count.htm create mode 100644 LANG_admin/vicidial_en/dbconnect.php create mode 100644 LANG_admin/vicidial_en/group_hourly_stats.php create mode 100644 LANG_admin/vicidial_en/help.gif create mode 100644 LANG_admin/vicidial_en/listloader.php create mode 100644 LANG_admin/vicidial_en/listloaderMAIN.php create mode 100644 LANG_admin/vicidial_en/new_listloader_superL.php create mode 100644 LANG_admin/vicidial_en/project_auth_entries.txt create mode 100644 LANG_admin/vicidial_en/remote_dispo.php create mode 100644 LANG_admin/vicidial_en/server_stats.php create mode 100644 LANG_admin/vicidial_en/user_stats.php create mode 100644 LANG_admin/vicidial_en/user_status.php create mode 100644 LANG_admin/vicidial_en/vdremote.php create mode 100644 LANG_admin/vicidial_es/AST_CLOSERstats.php create mode 100644 LANG_admin/vicidial_es/AST_VDADstats.php create mode 100644 LANG_admin/vicidial_es/AST_VICIDIAL_hopperlist.php create mode 100644 LANG_admin/vicidial_es/AST_admin_log_display.php create mode 100644 LANG_admin/vicidial_es/AST_agent_performance.php create mode 100644 LANG_admin/vicidial_es/AST_agent_performance_detail.php create mode 100644 LANG_admin/vicidial_es/AST_agent_time_sheet.php create mode 100644 LANG_admin/vicidial_es/AST_server_performance.php create mode 100644 LANG_admin/vicidial_es/AST_timeonVDAD.php create mode 100644 LANG_admin/vicidial_es/AST_timeonVDAD_closer.php create mode 100644 LANG_admin/vicidial_es/AST_timeonVDADall.php create mode 100644 LANG_admin/vicidial_es/AST_timeonVDADall_SIPmonitor.php create mode 100644 LANG_admin/vicidial_es/AST_timeoncall.php create mode 100644 LANG_admin/vicidial_es/AST_timeonpark.php create mode 100644 LANG_admin/vicidial_es/admin.php create mode 100644 LANG_admin/vicidial_es/admin_changes_log.txt create mode 100644 LANG_admin/vicidial_es/admin_modify_lead.php create mode 100644 LANG_admin/vicidial_es/admin_search_lead.php create mode 100644 LANG_admin/vicidial_es/count.htm create mode 100644 LANG_admin/vicidial_es/dbconnect.php create mode 100644 LANG_admin/vicidial_es/group_hourly_stats.php create mode 100644 LANG_admin/vicidial_es/help.gif create mode 100644 LANG_admin/vicidial_es/listloader.php create mode 100644 LANG_admin/vicidial_es/listloaderMAIN.php create mode 100644 LANG_admin/vicidial_es/new_listloader_superL.php create mode 100644 LANG_admin/vicidial_es/project_auth_entries.txt create mode 100644 LANG_admin/vicidial_es/remote_dispo.php create mode 100644 LANG_admin/vicidial_es/server_stats.php create mode 100644 LANG_admin/vicidial_es/user_stats.php create mode 100644 LANG_admin/vicidial_es/user_status.php create mode 100644 LANG_admin/vicidial_es/vdremote.php create mode 100644 LANG_agc.zip create mode 100644 LANG_agc/agc/active_list_refresh.php create mode 100644 LANG_agc/agc/astguiclient.php create mode 100644 LANG_agc/agc/calendar.php create mode 100644 LANG_agc/agc/call_log_display.php create mode 100644 LANG_agc/agc/conf_exten_check.php create mode 100644 LANG_agc/agc/dbconnect.php create mode 100644 LANG_agc/agc/fix-dispo-list.patch create mode 100644 LANG_agc/agc/images/agc_check_voicemail_BLINK.gif create mode 100644 LANG_agc/agc/images/agc_check_voicemail_BLINK_e.gif create mode 100644 LANG_agc/agc/images/agc_check_voicemail_BLINK_es.gif create mode 100644 LANG_agc/agc/images/agc_check_voicemail_BLINK_ptbr.gif create mode 100644 LANG_agc/agc/images/agc_check_voicemail_OFF.gif create mode 100644 LANG_agc/agc/images/agc_check_voicemail_OFF_es.gif create mode 100644 LANG_agc/agc/images/agc_check_voicemail_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/agc_check_voicemail_ON.gif create mode 100644 LANG_agc/agc/images/agc_check_voicemail_ON_es.gif create mode 100644 LANG_agc/agc/images/agc_check_voicemail_ON_ptbr.gif create mode 100644 LANG_agc/agc/images/agc_live_call_OFF.gif create mode 100644 LANG_agc/agc/images/agc_live_call_OFF_es.gif create mode 100644 LANG_agc/agc/images/agc_live_call_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/agc_live_call_ON.gif create mode 100644 LANG_agc/agc/images/agc_live_call_ON_es.gif create mode 100644 LANG_agc/agc/images/agc_live_call_ON_ptbr.gif create mode 100644 LANG_agc/agc/images/agc_tab_active_lines.gif create mode 100644 LANG_agc/agc/images/agc_tab_active_lines_es.gif create mode 100644 LANG_agc/agc/images/agc_tab_active_lines_ptbr.gif create mode 100644 LANG_agc/agc/images/agc_tab_astguiclient.gif create mode 100644 LANG_agc/agc/images/agc_tab_astguiclient_ptbr.gif create mode 100644 LANG_agc/agc/images/agc_tab_conferences.gif create mode 100644 LANG_agc/agc/images/agc_tab_conferences_es.gif create mode 100644 LANG_agc/agc/images/agc_tab_conferences_ptbr.gif create mode 100644 LANG_agc/agc/images/agc_tab_main.gif create mode 100644 LANG_agc/agc/images/agc_tab_main_es.gif create mode 100644 LANG_agc/agc/images/agc_tab_main_ptbr.gif create mode 100644 LANG_agc/agc/images/blank.gif create mode 100644 LANG_agc/agc/images/br.gif create mode 100644 LANG_agc/agc/images/de.gif create mode 100644 LANG_agc/agc/images/down.gif create mode 100644 LANG_agc/agc/images/el.gif create mode 100644 LANG_agc/agc/images/en.gif create mode 100644 LANG_agc/agc/images/es.gif create mode 100644 LANG_agc/agc/images/fr.gif create mode 100644 LANG_agc/agc/images/it.gif create mode 100644 LANG_agc/agc/images/pt.gif create mode 100644 LANG_agc/agc/images/remove.gif create mode 100644 LANG_agc/agc/images/up.gif create mode 100644 LANG_agc/agc/images/vdc_LB_dialnextnumber.gif create mode 100644 LANG_agc/agc/images/vdc_LB_dialnextnumber_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_LB_dialnextnumber_OFF_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_dialnextnumber_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_dialnextnumber_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_dialnextnumber_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_grabparkedcall.gif create mode 100644 LANG_agc/agc/images/vdc_LB_grabparkedcall_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_LB_grabparkedcall_OFF_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_grabparkedcall_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_grabparkedcall_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_grabparkedcall_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_hangupcustomer.gif create mode 100644 LANG_agc/agc/images/vdc_LB_hangupcustomer_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_LB_hangupcustomer_OFF_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_hangupcustomer_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_hangupcustomer_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_hangupcustomer_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_parkcall.gif create mode 100644 LANG_agc/agc/images/vdc_LB_parkcall_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_LB_parkcall_OFF_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_parkcall_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_parkcall_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_parkcall_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_pause.gif create mode 100644 LANG_agc/agc/images/vdc_LB_pause_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_LB_pause_OFF_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_pause_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_pause_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_pause_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_resume.gif create mode 100644 LANG_agc/agc/images/vdc_LB_resume_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_LB_resume_OFF_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_resume_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_resume_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_resume_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_senddtmf.gif create mode 100644 LANG_agc/agc/images/vdc_LB_senddtmf_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_LB_senddtmf_OFF_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_senddtmf_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_senddtmf_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_senddtmf_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_spacer.gif create mode 100644 LANG_agc/agc/images/vdc_LB_startrecording.gif create mode 100644 LANG_agc/agc/images/vdc_LB_startrecording_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_LB_startrecording_OFF_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_startrecording_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_startrecording_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_startrecording_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_stoprecording.gif create mode 100644 LANG_agc/agc/images/vdc_LB_stoprecording_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_LB_stoprecording_OFF_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_stoprecording_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_stoprecording_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_stoprecording_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_transferconf.gif create mode 100644 LANG_agc/agc/images/vdc_LB_transferconf_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_LB_transferconf_OFF_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_transferconf_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_transferconf_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_transferconf_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_webform.gif create mode 100644 LANG_agc/agc/images/vdc_LB_webform_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_LB_webform_OFF_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_webform_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_LB_webform_es.gif create mode 100644 LANG_agc/agc/images/vdc_LB_webform_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_ammessage.gif create mode 100644 LANG_agc/agc/images/vdc_XB_ammessage_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_XB_blindtransfer.gif create mode 100644 LANG_agc/agc/images/vdc_XB_blindtransfer_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_XB_blindtransfer_OFF_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_blindtransfer_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_blindtransfer_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_blindtransfer_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_channel.gif create mode 100644 LANG_agc/agc/images/vdc_XB_channel_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_channel_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_code.gif create mode 100644 LANG_agc/agc/images/vdc_XB_dialwithcustomer.gif create mode 100644 LANG_agc/agc/images/vdc_XB_dialwithcustomer_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_XB_dialwithcustomer_OFF_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_dialwithcustomer_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_dialwithcustomer_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_dialwithcustomer_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_hangupbothlines.gif create mode 100644 LANG_agc/agc/images/vdc_XB_hangupbothlines_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_XB_hangupbothlines_OFF_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_hangupbothlines_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_hangupbothlines_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_hangupbothlines_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_hangupxferline.gif create mode 100644 LANG_agc/agc/images/vdc_XB_hangupxferline_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_XB_hangupxferline_OFF_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_hangupxferline_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_hangupxferline_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_hangupxferline_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_header.gif create mode 100644 LANG_agc/agc/images/vdc_XB_header_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_header_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_hotkeysactive.gif create mode 100644 LANG_agc/agc/images/vdc_XB_hotkeysactive_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_XB_hotkeysactive_OFF_es-orig.gif create mode 100644 LANG_agc/agc/images/vdc_XB_hotkeysactive_OFF_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_hotkeysactive_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_hotkeysactive_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_hotkeysactive_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_hotkeysinactive_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_internalcloser.gif create mode 100644 LANG_agc/agc/images/vdc_XB_internalcloser_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_XB_internalcloser_OFF_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_internalcloser_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_internalcloser_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_internalcloser_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_leave3waycall.gif create mode 100644 LANG_agc/agc/images/vdc_XB_leave3waycall_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_XB_leave3waycall_OFF_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_leave3waycall_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_leave3waycall_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_leave3waycall_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_localcloser.gif create mode 100644 LANG_agc/agc/images/vdc_XB_localcloser_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_XB_localcloser_OFF_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_localcloser_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_localcloser_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_localcloser_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_number.gif create mode 100644 LANG_agc/agc/images/vdc_XB_number_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_number_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_parkcustomerdial.gif create mode 100644 LANG_agc/agc/images/vdc_XB_parkcustomerdial_OFF.gif create mode 100644 LANG_agc/agc/images/vdc_XB_parkcustomerdial_OFF_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_parkcustomerdial_OFF_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_parkcustomerdial_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_parkcustomerdial_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_XB_seconds.gif create mode 100644 LANG_agc/agc/images/vdc_XB_seconds_es.gif create mode 100644 LANG_agc/agc/images/vdc_XB_seconds_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_tab_script.gif create mode 100644 LANG_agc/agc/images/vdc_tab_script_es.gif create mode 100644 LANG_agc/agc/images/vdc_tab_script_ptbr.gif create mode 100644 LANG_agc/agc/images/vdc_tab_vicidial.gif create mode 100644 LANG_agc/agc/images/vdc_tab_vicidial_ptbr.gif create mode 100644 LANG_agc/agc/inbound_popup.php create mode 100644 LANG_agc/agc/live_exten_check.php create mode 100644 LANG_agc/agc/manager_send.php create mode 100644 LANG_agc/agc/park_calls_display.php create mode 100644 LANG_agc/agc/vdc_db_query.php create mode 100644 LANG_agc/agc/vicidial.php create mode 100644 LANG_agc/agc/voicemail_check.php create mode 100644 LANG_agc/agc_br/active_list_refresh.php create mode 100644 LANG_agc/agc_br/astguiclient.php create mode 100644 LANG_agc/agc_br/call_log_display.php create mode 100644 LANG_agc/agc_br/conf_exten_check.php create mode 100644 LANG_agc/agc_br/dbconnect.php create mode 100644 LANG_agc/agc_br/inbound_popup.php create mode 100644 LANG_agc/agc_br/live_exten_check.php create mode 100644 LANG_agc/agc_br/manager_send.php create mode 100644 LANG_agc/agc_br/park_calls_display.php create mode 100644 LANG_agc/agc_br/vdc_db_query.php create mode 100644 LANG_agc/agc_br/vicidial.php create mode 100644 LANG_agc/agc_br/voicemail_check.php create mode 100644 LANG_agc/agc_de/active_list_refresh.php create mode 100644 LANG_agc/agc_de/astguiclient.php create mode 100644 LANG_agc/agc_de/call_log_display.php create mode 100644 LANG_agc/agc_de/conf_exten_check.php create mode 100644 LANG_agc/agc_de/dbconnect.php create mode 100644 LANG_agc/agc_de/inbound_popup.php create mode 100644 LANG_agc/agc_de/live_exten_check.php create mode 100644 LANG_agc/agc_de/manager_send.php create mode 100644 LANG_agc/agc_de/park_calls_display.php create mode 100644 LANG_agc/agc_de/vdc_db_query.php create mode 100644 LANG_agc/agc_de/vicidial.php create mode 100644 LANG_agc/agc_de/voicemail_check.php create mode 100644 LANG_agc/agc_el/active_list_refresh.php create mode 100644 LANG_agc/agc_el/astguiclient.php create mode 100644 LANG_agc/agc_el/call_log_display.php create mode 100644 LANG_agc/agc_el/conf_exten_check.php create mode 100644 LANG_agc/agc_el/dbconnect.php create mode 100644 LANG_agc/agc_el/inbound_popup.php create mode 100644 LANG_agc/agc_el/live_exten_check.php create mode 100644 LANG_agc/agc_el/manager_send.php create mode 100644 LANG_agc/agc_el/park_calls_display.php create mode 100644 LANG_agc/agc_el/vdc_db_query.php create mode 100644 LANG_agc/agc_el/vicidial.php create mode 100644 LANG_agc/agc_el/voicemail_check.php create mode 100644 LANG_agc/agc_en/active_list_refresh.php create mode 100644 LANG_agc/agc_en/astguiclient.php create mode 100644 LANG_agc/agc_en/call_log_display.php create mode 100644 LANG_agc/agc_en/conf_exten_check.php create mode 100644 LANG_agc/agc_en/dbconnect.php create mode 100644 LANG_agc/agc_en/inbound_popup.php create mode 100644 LANG_agc/agc_en/live_exten_check.php create mode 100644 LANG_agc/agc_en/manager_send.php create mode 100644 LANG_agc/agc_en/park_calls_display.php create mode 100644 LANG_agc/agc_en/vdc_db_query.php create mode 100644 LANG_agc/agc_en/vicidial.php create mode 100644 LANG_agc/agc_en/voicemail_check.php create mode 100644 LANG_agc/agc_es/active_list_refresh.php create mode 100644 LANG_agc/agc_es/astguiclient.php create mode 100644 LANG_agc/agc_es/call_log_display.php create mode 100644 LANG_agc/agc_es/conf_exten_check.php create mode 100644 LANG_agc/agc_es/dbconnect.php create mode 100644 LANG_agc/agc_es/inbound_popup.php create mode 100644 LANG_agc/agc_es/live_exten_check.php create mode 100644 LANG_agc/agc_es/manager_send.php create mode 100644 LANG_agc/agc_es/park_calls_display.php create mode 100644 LANG_agc/agc_es/vdc_db_query.php create mode 100644 LANG_agc/agc_es/vicidial.php create mode 100644 LANG_agc/agc_es/voicemail_check.php create mode 100644 LANG_agc/agc_fr/active_list_refresh.php create mode 100644 LANG_agc/agc_fr/astguiclient.php create mode 100644 LANG_agc/agc_fr/call_log_display.php create mode 100644 LANG_agc/agc_fr/conf_exten_check.php create mode 100644 LANG_agc/agc_fr/dbconnect.php create mode 100644 LANG_agc/agc_fr/inbound_popup.php create mode 100644 LANG_agc/agc_fr/live_exten_check.php create mode 100644 LANG_agc/agc_fr/manager_send.php create mode 100644 LANG_agc/agc_fr/park_calls_display.php create mode 100644 LANG_agc/agc_fr/vdc_db_query.php create mode 100644 LANG_agc/agc_fr/vicidial.php create mode 100644 LANG_agc/agc_fr/voicemail_check.php create mode 100644 LANG_agc/agc_it/active_list_refresh.php create mode 100644 LANG_agc/agc_it/astguiclient.php create mode 100644 LANG_agc/agc_it/call_log_display.php create mode 100644 LANG_agc/agc_it/conf_exten_check.php create mode 100644 LANG_agc/agc_it/dbconnect.php create mode 100644 LANG_agc/agc_it/inbound_popup.php create mode 100644 LANG_agc/agc_it/live_exten_check.php create mode 100644 LANG_agc/agc_it/manager_send.php create mode 100644 LANG_agc/agc_it/park_calls_display.php create mode 100644 LANG_agc/agc_it/vdc_db_query.php create mode 100644 LANG_agc/agc_it/vicidial.php create mode 100644 LANG_agc/agc_it/voicemail_check.php create mode 100644 LANG_agc/agc_pt/active_list_refresh.php create mode 100644 LANG_agc/agc_pt/astguiclient.php create mode 100644 LANG_agc/agc_pt/call_log_display.php create mode 100644 LANG_agc/agc_pt/conf_exten_check.php create mode 100644 LANG_agc/agc_pt/dbconnect.php create mode 100644 LANG_agc/agc_pt/inbound_popup.php create mode 100644 LANG_agc/agc_pt/live_exten_check.php create mode 100644 LANG_agc/agc_pt/manager_send.php create mode 100644 LANG_agc/agc_pt/park_calls_display.php create mode 100644 LANG_agc/agc_pt/vdc_db_query.php create mode 100644 LANG_agc/agc_pt/vicidial.php create mode 100644 LANG_agc/agc_pt/voicemail_check.php create mode 100644 MySQL_AST_CREATE_tables.sql create mode 100644 VD_amd.agi create mode 100644 VD_amd_post.agi create mode 100644 VD_app_conference_0.6.zip create mode 100644 VD_hangup.agi create mode 100644 VICIDIAL_IN_new_leads_file.pl create mode 100644 VICIDIAL_web/AST_CLOSERstats.php create mode 100644 VICIDIAL_web/AST_VDADstats.php create mode 100644 VICIDIAL_web/AST_VICIDIAL_hopperlist.php create mode 100644 VICIDIAL_web/AST_admin_log_display.php create mode 100644 VICIDIAL_web/AST_agent_performance.php create mode 100644 VICIDIAL_web/AST_agent_performance_detail.php create mode 100644 VICIDIAL_web/AST_agent_time_sheet.php create mode 100644 VICIDIAL_web/AST_agent_time_sheet_archive.php create mode 100644 VICIDIAL_web/AST_parkstats.php create mode 100644 VICIDIAL_web/AST_server_performance.php create mode 100644 VICIDIAL_web/AST_timeonVDAD.php create mode 100644 VICIDIAL_web/AST_timeonVDAD_closer.php create mode 100644 VICIDIAL_web/AST_timeonVDADall.php create mode 100644 VICIDIAL_web/AST_timeonVDADall_SIPmonitor.php create mode 100644 VICIDIAL_web/AST_timeoncall.php create mode 100644 VICIDIAL_web/AST_timeonpark.php create mode 100644 VICIDIAL_web/admin.php create mode 100644 VICIDIAL_web/admin_modify_lead.php create mode 100644 VICIDIAL_web/admin_search_lead.php create mode 100644 VICIDIAL_web/closer-fronter_popup.php create mode 100644 VICIDIAL_web/closer-fronter_popup2.php create mode 100644 VICIDIAL_web/closer.php create mode 100644 VICIDIAL_web/closer_dispo.php create mode 100644 VICIDIAL_web/closer_popup.php create mode 100644 VICIDIAL_web/count.htm create mode 100644 VICIDIAL_web/dbconnect.php create mode 100644 VICIDIAL_web/group_hourly_stats.php create mode 100644 VICIDIAL_web/help.gif create mode 100644 VICIDIAL_web/listloader.php create mode 100644 VICIDIAL_web/listloader.pl create mode 100644 VICIDIAL_web/listloaderMAIN.php create mode 100644 VICIDIAL_web/listloader_rowdisplay.pl create mode 100644 VICIDIAL_web/listloader_super.pl create mode 100644 VICIDIAL_web/log_test.php create mode 100644 VICIDIAL_web/new_listloader_superL.php create mode 100644 VICIDIAL_web/record_conf_1_hour.php create mode 100644 VICIDIAL_web/remote_dispo.php create mode 100644 VICIDIAL_web/server_stats.php create mode 100644 VICIDIAL_web/test.txt create mode 100644 VICIDIAL_web/user_stats.php create mode 100644 VICIDIAL_web/user_status.php create mode 100644 VICIDIAL_web/vdremote.php create mode 100644 agc/active_list_refresh.php create mode 100644 agc/astguiclient.php create mode 100644 agc/call_log_display.php create mode 100644 agc/conf_exten_check.php create mode 100644 agc/dbconnect.php create mode 100644 agc/images/agc_check_voicemail_BLINK.gif create mode 100644 agc/images/agc_check_voicemail_BLINK_e.gif create mode 100644 agc/images/agc_check_voicemail_BLINK_es.gif create mode 100644 agc/images/agc_check_voicemail_BLINK_ptbr.gif create mode 100644 agc/images/agc_check_voicemail_OFF.gif create mode 100644 agc/images/agc_check_voicemail_OFF_es.gif create mode 100644 agc/images/agc_check_voicemail_OFF_ptbr.gif create mode 100644 agc/images/agc_check_voicemail_ON.gif create mode 100644 agc/images/agc_check_voicemail_ON_es.gif create mode 100644 agc/images/agc_check_voicemail_ON_ptbr.gif create mode 100644 agc/images/agc_live_call_OFF.gif create mode 100644 agc/images/agc_live_call_OFF_es.gif create mode 100644 agc/images/agc_live_call_OFF_ptbr.gif create mode 100644 agc/images/agc_live_call_ON.gif create mode 100644 agc/images/agc_live_call_ON_es.gif create mode 100644 agc/images/agc_live_call_ON_ptbr.gif create mode 100644 agc/images/agc_tab_active_lines.gif create mode 100644 agc/images/agc_tab_active_lines_el.gif create mode 100644 agc/images/agc_tab_active_lines_es.gif create mode 100644 agc/images/agc_tab_active_lines_ptbr.gif create mode 100644 agc/images/agc_tab_astguiclient.gif create mode 100644 agc/images/agc_tab_astguiclient_ptbr.gif create mode 100644 agc/images/agc_tab_conferences.gif create mode 100644 agc/images/agc_tab_conferences_el.gif create mode 100644 agc/images/agc_tab_conferences_es.gif create mode 100644 agc/images/agc_tab_conferences_ptbr.gif create mode 100644 agc/images/agc_tab_main.gif create mode 100644 agc/images/agc_tab_main_el.gif create mode 100644 agc/images/agc_tab_main_es.gif create mode 100644 agc/images/agc_tab_main_ptbr.gif create mode 100644 agc/images/blank.gif create mode 100644 agc/images/br.gif create mode 100644 agc/images/de.gif create mode 100644 agc/images/down.gif create mode 100644 agc/images/el.gif create mode 100644 agc/images/en.gif create mode 100644 agc/images/es.gif create mode 100644 agc/images/fr.gif create mode 100644 agc/images/it.gif create mode 100644 agc/images/pt.gif create mode 100644 agc/images/remove.gif create mode 100644 agc/images/up.gif create mode 100644 agc/images/vdc_LB_dialnextnumber.gif create mode 100644 agc/images/vdc_LB_dialnextnumber_OFF.gif create mode 100644 agc/images/vdc_LB_dialnextnumber_OFF_es.gif create mode 100644 agc/images/vdc_LB_dialnextnumber_OFF_ptbr.gif create mode 100644 agc/images/vdc_LB_dialnextnumber_es.gif create mode 100644 agc/images/vdc_LB_dialnextnumber_ptbr.gif create mode 100644 agc/images/vdc_LB_grabparkedcall.gif create mode 100644 agc/images/vdc_LB_grabparkedcall_OFF.gif create mode 100644 agc/images/vdc_LB_grabparkedcall_OFF_es.gif create mode 100644 agc/images/vdc_LB_grabparkedcall_OFF_ptbr.gif create mode 100644 agc/images/vdc_LB_grabparkedcall_es.gif create mode 100644 agc/images/vdc_LB_grabparkedcall_ptbr.gif create mode 100644 agc/images/vdc_LB_hangupcustomer.gif create mode 100644 agc/images/vdc_LB_hangupcustomer_OFF.gif create mode 100644 agc/images/vdc_LB_hangupcustomer_OFF_es.gif create mode 100644 agc/images/vdc_LB_hangupcustomer_OFF_ptbr.gif create mode 100644 agc/images/vdc_LB_hangupcustomer_es.gif create mode 100644 agc/images/vdc_LB_hangupcustomer_ptbr.gif create mode 100644 agc/images/vdc_LB_parkcall.gif create mode 100644 agc/images/vdc_LB_parkcall_OFF.gif create mode 100644 agc/images/vdc_LB_parkcall_OFF_es.gif create mode 100644 agc/images/vdc_LB_parkcall_OFF_ptbr.gif create mode 100644 agc/images/vdc_LB_parkcall_es.gif create mode 100644 agc/images/vdc_LB_parkcall_ptbr.gif create mode 100644 agc/images/vdc_LB_pause.gif create mode 100644 agc/images/vdc_LB_pause_OFF.gif create mode 100644 agc/images/vdc_LB_pause_OFF_es.gif create mode 100644 agc/images/vdc_LB_pause_OFF_ptbr.gif create mode 100644 agc/images/vdc_LB_pause_es.gif create mode 100644 agc/images/vdc_LB_pause_ptbr.gif create mode 100644 agc/images/vdc_LB_resume.gif create mode 100644 agc/images/vdc_LB_resume_OFF.gif create mode 100644 agc/images/vdc_LB_resume_OFF_es.gif create mode 100644 agc/images/vdc_LB_resume_OFF_ptbr.gif create mode 100644 agc/images/vdc_LB_resume_es.gif create mode 100644 agc/images/vdc_LB_resume_ptbr.gif create mode 100644 agc/images/vdc_LB_senddtmf.gif create mode 100644 agc/images/vdc_LB_senddtmf_OFF.gif create mode 100644 agc/images/vdc_LB_senddtmf_OFF_es.gif create mode 100644 agc/images/vdc_LB_senddtmf_OFF_ptbr.gif create mode 100644 agc/images/vdc_LB_senddtmf_es.gif create mode 100644 agc/images/vdc_LB_senddtmf_ptbr.gif create mode 100644 agc/images/vdc_LB_spacer.gif create mode 100644 agc/images/vdc_LB_startrecording.gif create mode 100644 agc/images/vdc_LB_startrecording_OFF.gif create mode 100644 agc/images/vdc_LB_startrecording_OFF_es.gif create mode 100644 agc/images/vdc_LB_startrecording_OFF_ptbr.gif create mode 100644 agc/images/vdc_LB_startrecording_es.gif create mode 100644 agc/images/vdc_LB_startrecording_ptbr.gif create mode 100644 agc/images/vdc_LB_stoprecording.gif create mode 100644 agc/images/vdc_LB_stoprecording_OFF.gif create mode 100644 agc/images/vdc_LB_stoprecording_OFF_es.gif create mode 100644 agc/images/vdc_LB_stoprecording_OFF_ptbr.gif create mode 100644 agc/images/vdc_LB_stoprecording_es.gif create mode 100644 agc/images/vdc_LB_stoprecording_ptbr.gif create mode 100644 agc/images/vdc_LB_transferconf.gif create mode 100644 agc/images/vdc_LB_transferconf_OFF.gif create mode 100644 agc/images/vdc_LB_transferconf_OFF_es.gif create mode 100644 agc/images/vdc_LB_transferconf_OFF_ptbr.gif create mode 100644 agc/images/vdc_LB_transferconf_es.gif create mode 100644 agc/images/vdc_LB_transferconf_ptbr.gif create mode 100644 agc/images/vdc_LB_webform.gif create mode 100644 agc/images/vdc_LB_webform_OFF.gif create mode 100644 agc/images/vdc_LB_webform_OFF_es.gif create mode 100644 agc/images/vdc_LB_webform_OFF_ptbr.gif create mode 100644 agc/images/vdc_LB_webform_es.gif create mode 100644 agc/images/vdc_LB_webform_ptbr.gif create mode 100644 agc/images/vdc_XB_ammessage.gif create mode 100644 agc/images/vdc_XB_ammessage_OFF.gif create mode 100644 agc/images/vdc_XB_blindtransfer.gif create mode 100644 agc/images/vdc_XB_blindtransfer_OFF.gif create mode 100644 agc/images/vdc_XB_blindtransfer_OFF_es.gif create mode 100644 agc/images/vdc_XB_blindtransfer_OFF_ptbr.gif create mode 100644 agc/images/vdc_XB_blindtransfer_es.gif create mode 100644 agc/images/vdc_XB_blindtransfer_ptbr.gif create mode 100644 agc/images/vdc_XB_channel.gif create mode 100644 agc/images/vdc_XB_channel_es.gif create mode 100644 agc/images/vdc_XB_channel_ptbr.gif create mode 100644 agc/images/vdc_XB_code.gif create mode 100644 agc/images/vdc_XB_dialwithcustomer.gif create mode 100644 agc/images/vdc_XB_dialwithcustomer_OFF.gif create mode 100644 agc/images/vdc_XB_dialwithcustomer_OFF_es.gif create mode 100644 agc/images/vdc_XB_dialwithcustomer_OFF_ptbr.gif create mode 100644 agc/images/vdc_XB_dialwithcustomer_es.gif create mode 100644 agc/images/vdc_XB_dialwithcustomer_ptbr.gif create mode 100644 agc/images/vdc_XB_hangupbothlines.gif create mode 100644 agc/images/vdc_XB_hangupbothlines_OFF.gif create mode 100644 agc/images/vdc_XB_hangupbothlines_OFF_es.gif create mode 100644 agc/images/vdc_XB_hangupbothlines_OFF_ptbr.gif create mode 100644 agc/images/vdc_XB_hangupbothlines_es.gif create mode 100644 agc/images/vdc_XB_hangupbothlines_ptbr.gif create mode 100644 agc/images/vdc_XB_hangupxferline.gif create mode 100644 agc/images/vdc_XB_hangupxferline_OFF.gif create mode 100644 agc/images/vdc_XB_hangupxferline_OFF_es.gif create mode 100644 agc/images/vdc_XB_hangupxferline_OFF_ptbr.gif create mode 100644 agc/images/vdc_XB_hangupxferline_es.gif create mode 100644 agc/images/vdc_XB_hangupxferline_ptbr.gif create mode 100644 agc/images/vdc_XB_header.gif create mode 100644 agc/images/vdc_XB_header_es.gif create mode 100644 agc/images/vdc_XB_header_ptbr.gif create mode 100644 agc/images/vdc_XB_hotkeysactive.gif create mode 100644 agc/images/vdc_XB_hotkeysactive_OFF.gif create mode 100644 agc/images/vdc_XB_hotkeysactive_OFF_es-orig.gif create mode 100644 agc/images/vdc_XB_hotkeysactive_OFF_es.gif create mode 100644 agc/images/vdc_XB_hotkeysactive_OFF_ptbr.gif create mode 100644 agc/images/vdc_XB_hotkeysactive_es.gif create mode 100644 agc/images/vdc_XB_hotkeysactive_ptbr.gif create mode 100644 agc/images/vdc_XB_hotkeysinactive_es.gif create mode 100644 agc/images/vdc_XB_internalcloser.gif create mode 100644 agc/images/vdc_XB_internalcloser_OFF.gif create mode 100644 agc/images/vdc_XB_internalcloser_OFF_es.gif create mode 100644 agc/images/vdc_XB_internalcloser_OFF_ptbr.gif create mode 100644 agc/images/vdc_XB_internalcloser_es.gif create mode 100644 agc/images/vdc_XB_internalcloser_ptbr.gif create mode 100644 agc/images/vdc_XB_leave3waycall.gif create mode 100644 agc/images/vdc_XB_leave3waycall_OFF.gif create mode 100644 agc/images/vdc_XB_leave3waycall_OFF_es.gif create mode 100644 agc/images/vdc_XB_leave3waycall_OFF_ptbr.gif create mode 100644 agc/images/vdc_XB_leave3waycall_es.gif create mode 100644 agc/images/vdc_XB_leave3waycall_ptbr.gif create mode 100644 agc/images/vdc_XB_localcloser.gif create mode 100644 agc/images/vdc_XB_localcloser_OFF.gif create mode 100644 agc/images/vdc_XB_localcloser_OFF_es.gif create mode 100644 agc/images/vdc_XB_localcloser_OFF_ptbr.gif create mode 100644 agc/images/vdc_XB_localcloser_es.gif create mode 100644 agc/images/vdc_XB_localcloser_ptbr.gif create mode 100644 agc/images/vdc_XB_number.gif create mode 100644 agc/images/vdc_XB_number_es.gif create mode 100644 agc/images/vdc_XB_number_ptbr.gif create mode 100644 agc/images/vdc_XB_parkcustomerdial.gif create mode 100644 agc/images/vdc_XB_parkcustomerdial_OFF.gif create mode 100644 agc/images/vdc_XB_parkcustomerdial_OFF_es.gif create mode 100644 agc/images/vdc_XB_parkcustomerdial_OFF_ptbr.gif create mode 100644 agc/images/vdc_XB_parkcustomerdial_es.gif create mode 100644 agc/images/vdc_XB_parkcustomerdial_ptbr.gif create mode 100644 agc/images/vdc_XB_seconds.gif create mode 100644 agc/images/vdc_XB_seconds_es.gif create mode 100644 agc/images/vdc_XB_seconds_ptbr.gif create mode 100644 agc/images/vdc_tab_script.gif create mode 100644 agc/images/vdc_tab_script_es.gif create mode 100644 agc/images/vdc_tab_script_ptbr.gif create mode 100644 agc/images/vdc_tab_vicidial.gif create mode 100644 agc/images/vdc_tab_vicidial_ptbr.gif create mode 100644 agc/inbound_popup.php create mode 100644 agc/live_exten_check.php create mode 100644 agc/manager_send.php create mode 100644 agc/park_calls_display.php create mode 100644 agc/vdc_db_query.php create mode 100644 agc/vicidial.php create mode 100644 agc/voicemail_check.php create mode 100644 agi-CIDtest.agi create mode 100644 agi-VDAD_LB_closer.agi create mode 100644 agi-VDAD_LB_closer_inbound.agi create mode 100644 agi-VDAD_LB_transfer.agi create mode 100644 agi-VDAD_LO_closer.agi create mode 100644 agi-VDAD_LO_closer_inbound.agi create mode 100644 agi-VDAD_LO_transfer.agi create mode 100644 agi-VDADautoREMINDER.agi create mode 100644 agi-VDADautoREMINDERxfer.agi create mode 100644 agi-VDADcloser.agi create mode 100644 agi-VDADcloser_PHONE.agi create mode 100644 agi-VDADcloser_inbound.agi create mode 100644 agi-VDADcloser_inboundANI.agi create mode 100644 agi-VDADcloser_inboundCID-debug.agi create mode 100644 agi-VDADcloser_inboundCID.agi create mode 100644 agi-VDADcloser_inboundCIDlookup.agi create mode 100644 agi-VDADcloser_inbound_5ID.agi create mode 100644 agi-VDADcloser_inbound_NOCID.agi create mode 100644 agi-VDADlisten_DTMF.agi create mode 100644 agi-VDADtransfer.agi create mode 100644 agi-VDADtransferSURVEY.agi create mode 100644 agi-dtmf.agi create mode 100644 agi-record_prompts.agi create mode 100644 app_conference/0.gsm create mode 100644 app_conference/0.wav create mode 100644 app_conference/1.gsm create mode 100644 app_conference/1.wav create mode 100644 app_conference/2.gsm create mode 100644 app_conference/2.wav create mode 100644 app_conference/3.gsm create mode 100644 app_conference/3.wav create mode 100644 app_conference/4.gsm create mode 100644 app_conference/4.wav create mode 100644 app_conference/5.gsm create mode 100644 app_conference/5.wav create mode 100644 app_conference/6.gsm create mode 100644 app_conference/6.wav create mode 100644 app_conference/64_Makefile create mode 100644 app_conference/7.gsm create mode 100644 app_conference/7.wav create mode 100644 app_conference/8.gsm create mode 100644 app_conference/8.wav create mode 100644 app_conference/9.gsm create mode 100644 app_conference/9.wav create mode 100644 app_conference/LICENSE create mode 100644 app_conference/Makefile create mode 100644 app_conference/README create mode 100644 app_conference/VICIDIAL.txt create mode 100644 app_conference/app_conference.c create mode 100644 app_conference/app_conference.h create mode 100644 app_conference/cli.c create mode 100644 app_conference/cli.h create mode 100644 app_conference/common.h create mode 100644 app_conference/conf_frame.h create mode 100644 app_conference/conference.c create mode 100644 app_conference/conference.h create mode 100644 app_conference/enter.gsm create mode 100644 app_conference/frame.c create mode 100644 app_conference/frame.h create mode 100644 app_conference/hash.gsm create mode 100644 app_conference/hash.wav create mode 100644 app_conference/leave.gsm create mode 100644 app_conference/libspeex/CVS/Entries create mode 100644 app_conference/libspeex/CVS/Repository create mode 100644 app_conference/libspeex/CVS/Root create mode 100644 app_conference/libspeex/misc.c create mode 100644 app_conference/libspeex/misc.h create mode 100644 app_conference/libspeex/preprocess.c create mode 100644 app_conference/libspeex/qc_20060323.zip create mode 100644 app_conference/libspeex/smallft.c create mode 100644 app_conference/libspeex/smallft.h create mode 100644 app_conference/libspeex/speex_preprocess.h create mode 100644 app_conference/member.c create mode 100644 app_conference/member.h create mode 100644 app_conference/star.gsm create mode 100644 app_conference/star.wav create mode 100644 astLEADLOADER.pl create mode 100644 astguiclient_web/AST_inboundEXTstats.php create mode 100644 astguiclient_web/admin.php create mode 100644 astguiclient_web/dbconnect.php create mode 100644 astguiclient_web/help.gif create mode 100644 astguiclient_web/inbound_popup.php create mode 100644 astguiclient_web/phone_stats.php create mode 100644 astguiclient_web/remote_inbound.php create mode 100644 astguiclient_web/test.php create mode 100644 call_inbound.agi create mode 100644 call_log.agi create mode 100644 call_logCID.agi create mode 100644 call_park.agi create mode 100644 call_park_EXT.agi create mode 100644 call_park_I.agi create mode 100644 call_park_L.agi create mode 100644 call_park_W.agi create mode 100644 debug_speak.agi create mode 100644 docs/ACQS.txt create mode 100644 docs/APP_CONFERENCE.txt create mode 100644 docs/CALLBACKS_PROCESS.txt create mode 100644 docs/CONF_Asterisk.txt create mode 100644 docs/CONF_MySQL.txt create mode 100644 docs/CONF_VICIDIAL_MySQL.txt create mode 100644 docs/LICENSE.txt create mode 100644 docs/LOAD_BALANCING.txt create mode 100644 docs/README.txt create mode 100644 docs/REQUIREMENTS.txt create mode 100644 docs/SCRATCH_INSTALL.txt create mode 100644 docs/TODO.txt create mode 100644 docs/TODO_1.1.11.txt create mode 100644 docs/TODO_1.1.12.txt create mode 100644 docs/VICIDIAL.txt create mode 100644 install_server_files.pl create mode 100644 invalid_speak.agi create mode 100644 libs/AST_VICI_conf.pl.bak create mode 100644 libs/AUS_zipcode_ranges.txt create mode 100644 libs/Asterisk.pm create mode 100644 libs/Asterisk/AGI.pm create mode 100644 libs/Asterisk/DONOTUSE_AST_VICI_conf.pl create mode 100644 libs/Asterisk/Manager.pm create mode 100644 libs/Asterisk/Outgoing.pm create mode 100644 libs/Asterisk/QCall.pm create mode 100644 libs/Asterisk/Voicemail.pm create mode 100644 libs/Asterisk/buttons.gif create mode 100644 libs/Asterisk/vm_indicator_anim.gif create mode 100644 libs/Asterisk/voicemail_digits.gif create mode 100644 libs/Asterisk/voicemail_new.gif create mode 100644 libs/Asterisk/voicemail_old.gif create mode 100644 libs/Asterisk/voicemail_up.gif create mode 100644 libs/MySQL.pm create mode 100644 libs/Net/HTTP.pm create mode 100644 libs/Net/HTTP/Methods.pm create mode 100644 libs/Net/HTTP/NB.pm create mode 100644 libs/Net/HTTPS.pm create mode 100644 libs/Net/MySQL.pm create mode 100644 libs/Net/SSH.pm create mode 100644 libs/Net/Telnet.pm create mode 100644 libs/Telnet.pm create mode 100644 libs/Time/HiRes.1.59.pm create mode 100644 libs/Time/HiRes.1.65.pm create mode 100644 libs/Time/HiRes.pm create mode 100644 libs/Time/Local.pm create mode 100644 libs/Time/Other_HiRes_versions/HiRes.1.55.pm create mode 100644 libs/Time/Other_HiRes_versions/HiRes.1.59.pm create mode 100644 libs/Time/Other_HiRes_versions/HiRes.1.65.pm create mode 100644 libs/Time/Other_HiRes_versions/HiRes.pm create mode 100644 libs/Time/gmtime.pm create mode 100644 libs/Time/localtime.pm create mode 100644 libs/Time/tm.pm create mode 100644 libs/US_zipcode_ranges.txt create mode 100644 newt-0.51.6.tar.gz create mode 100644 park_CID.agi create mode 100644 phone_codes_GMT.txt create mode 100644 sphinxNA.zip create mode 100644 start_asterisk_boot.pl create mode 100644 testMULTI_VICIDIAL_lead_file.csv create mode 100644 testMULTI_VICIDIAL_lead_file.txt create mode 100644 testMULTI_VICIDIAL_lead_file.xls create mode 100644 test_VICIDIAL_lead_file.txt create mode 100644 translations/br_language.txt create mode 100644 translations/de_language.txt create mode 100644 translations/de_language_admin.txt create mode 100644 translations/el_language.txt create mode 100644 translations/el_language_admin.txt create mode 100644 translations/es_language.txt create mode 100644 translations/es_language_admin.txt create mode 100644 translations/fr_language.txt create mode 100644 translations/it_language.txt create mode 100644 translations/pt_language.txt create mode 100644 translations/raw_translation_files/TO_BE_TRANSLATED_admin_1.1.12_de.txt create mode 100644 translations/raw_translation_files/language.txt create mode 100644 translations/raw_translation_files/language_admin.txt create mode 100644 translations/raw_translation_files/languages.txt_en_de create mode 100644 translations/raw_translation_files/languages.txt_en_el create mode 100644 translations/raw_translation_files/languages.txt_en_es create mode 100644 translations/raw_translation_files/languages.txt_en_fr create mode 100644 translations/raw_translation_files/languages.txt_en_it create mode 100644 translations/raw_translation_files/languages.txt_en_pt diff --git a/ADMIN_adjust_GMTnow_on_leads.pl b/ADMIN_adjust_GMTnow_on_leads.pl new file mode 100644 index 00000000..ab4ed81d --- /dev/null +++ b/ADMIN_adjust_GMTnow_on_leads.pl @@ -0,0 +1,688 @@ +#!/usr/bin/perl + +# ADMIN_adjust_GMTnow_on_leads.pl +# +# program goes throught the vicidial_list table and adjusts the gmt_offset_now +# field to change it to today's offset if needed because of Daylight Saving Time +# +# run every time you load leads into the vicidial_list table +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# +# +# 50810-1540 - Added database server variable definitions lookup +# 60615-1717 - Added definition GMT lookup from database not flat text file +# + +$MT[0]=''; + +### begin parsing run-time options ### +if (length($ARGV[0])>1) +{ + $i=0; + while ($#ARGV >= $i) + { + $args = "$args $ARGV[$i]"; + $i++; + } + + if ($args =~ /--help/i) + { + print "allowed run time options:\n [-q] = quiet\n [-t] = test\n [--debug] = debugging messages\n\n"; + } + else + { + if ($args =~ /-q/i) + { + $q=1; $Q=1; + } + if ($args =~ /--debug/i) + { + $DB=1; + print "\n-----DEBUGGING -----\n\n"; + } + if ($args =~ /--debugX/i) + { + $DBX=1; + print "\n----- SUPER-DUPER DEBUGGING -----\n\n"; + } + if ($args =~ /-t|--test/i) + { + $T=1; $TEST=1; + print "\n-----TESTING -----\n\n"; + } + } +} +else +{ +print "no command line options set\n"; +} + +if ($DB) {print "STARTING TIME ZONE DAYLIGHT SAVING TIME CALCULATION SCRIPT\n\n\n\n";} + +### end parsing run-time options ### + +### Make sure this file is in a libs path or put the absolute path to it +require("/home/cron/AST_SERVER_conf.pl"); # local configuration file + +if (!$DB_port) {$DB_port='3306';} + +$secX = time(); +# $secX = '1079989363'; # epoch for March 22, 2993 +# $secX = '1097989363'; # epoch for October 17, 2004 + + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($secX); + $mon++; + $year = ($year + 1900); + if ($mon < 10) {$mon = "0$mon";} + if ($mday < 10) {$mday = "0$mday";} + if ($hour < 10) {$hour = "0$hour";} + if ($min < 10) {$min = "0$min";} + if ($sec < 10) {$sec = "0$sec";} + $dsec = ( ( ($hour * 3600) + ($min * 60) ) + $sec ); + +use Net::MySQL; + + my $dbhA = Net::MySQL->new(hostname => "$DB_server", database => "$DB_database", user => "$DB_user", password => "$DB_pass", port => "$DB_port") + or die "Couldn't connect to database: $DB_server - $DB_database\n"; + + + ### Grab Server values from the database + $stmtA = "SELECT telnet_host,telnet_port,ASTmgrUSERNAME,ASTmgrSECRET,ASTmgrUSERNAMEupdate,ASTmgrUSERNAMElisten,ASTmgrUSERNAMEsend,max_vicidial_trunks,answer_transfer_agent,local_gmt,ext_context FROM servers where server_ip = '$server_ip';"; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $DBtelnet_host = "$record->[0]"; + $DBtelnet_port = "$record->[1]"; + $DBASTmgrUSERNAME = "$record->[2]"; + $DBASTmgrSECRET = "$record->[3]"; + $DBASTmgrUSERNAMEupdate = "$record->[4]"; + $DBASTmgrUSERNAMElisten = "$record->[5]"; + $DBASTmgrUSERNAMEsend = "$record->[6]"; + $DBmax_vicidial_trunks = "$record->[7]"; + $DBanswer_transfer_agent= "$record->[8]"; + $DBSERVER_GMT = "$record->[9]"; + $DBext_context = "$record->[10]"; + if ($DBtelnet_host) {$telnet_host = $DBtelnet_host;} + if ($DBtelnet_port) {$telnet_port = $DBtelnet_port;} + if ($DBASTmgrUSERNAME) {$ASTmgrUSERNAME = $DBASTmgrUSERNAME;} + if ($DBASTmgrSECRET) {$ASTmgrSECRET = $DBASTmgrSECRET;} + if ($DBASTmgrUSERNAMEupdate) {$ASTmgrUSERNAMEupdate = $DBASTmgrUSERNAMEupdate;} + if ($DBASTmgrUSERNAMElisten) {$ASTmgrUSERNAMElisten = $DBASTmgrUSERNAMElisten;} + if ($DBASTmgrUSERNAMEsend) {$ASTmgrUSERNAMEsend = $DBASTmgrUSERNAMEsend;} + if ($DBmax_vicidial_trunks) {$max_vicidial_trunks = $DBmax_vicidial_trunks;} + if ($DBanswer_transfer_agent) {$answer_transfer_agent = $DBanswer_transfer_agent;} + if ($DBSERVER_GMT) {$SERVER_GMT = $DBSERVER_GMT;} + if ($DBext_context) {$ext_context = $DBext_context;} + } + } + + $LOCAL_GMT_OFF = $SERVER_GMT; + $LOCAL_GMT_OFF_STD = $SERVER_GMT; + +if ($isdst) {$LOCAL_GMT_OFF++;} +if ($DB) {print "SEED TIME $secX : $year-$mon-$mday $hour:$min:$sec LOCAL GMT OFFSET NOW: $LOCAL_GMT_OFF\n";} + + + $stmtA = "select distinct phone_code from vicidial_list;"; + if($DBX){print STDERR "\n|$stmtA|\n";} + $dbhA->query($stmtA); + if ($dbhA->has_selected_record) + { + $iterA=$dbhA->create_record_iterator; + $rec_countY=0; + @phone_codes=@MT; + $phone_codes_list='|'; + while ($recordA = $iterA->each) + { + $phone_codes[$rec_countY] = $recordA->[0]; + $phone_codes_ORIG[$rec_countY] = $recordA->[0]; + $phone_codes[$rec_countY] =~ s/011|0011| |\t|\r|\n//gi; + + # if ( ($phone_codes_list !~ /\|$phone_codes[$rec_countY]\|/) && (length($phone_codes[$rec_countY]) > 0) ) + # { + # $phone_codes_list .= "$phone_codes[$rec_countY]|"; + # } + + if ($DBX) {print "|",$recordA->[0],"|","\n";} + $rec_countY++; + } + } + + if ($DB) {print " - Unique Country dial codes found: $rec_countY\n";} + + + $stmtA = "select * from vicidial_phone_codes;"; + if($DBX){print STDERR "\n|$stmtA|\n";} + $dbhA->query($stmtA); + if ($dbhA->has_selected_record) + { + $iterA=$dbhA->create_record_iterator; + $rec_countZ=0; + @codefile=@MT; + while ($recordA = $iterA->each) + { + $codefile[$rec_countZ] = "$recordA->[0]\t$recordA->[1]\t$recordA->[2]\t$recordA->[3]\t$recordA->[4]\t$recordA->[5]\t$recordA->[6]\t$recordA->[7]\n"; + $rec_countZ++; + } + } + + if ($DB) {print " - GMT phone codes records: $rec_countZ\n";} + +# open(codefile, "/home/cron/phone_codes_GMT.txt") || die "can't open /home/cron/phone_codes_GMT.txt: $!\n"; +# @codefile = ; +# close(codefile); + +$ep=0; $ei=0; $ee=0; +$d=0; +foreach (@phone_codes) + { + $match_code = $phone_codes[$d]; + $match_code_ORIG = $phone_codes_ORIG[$d]; + + if ($DB) {print "\nRUNNING LOOP FOR COUNTRY CODE: $match_code\n";} + + $e=0; + foreach (@codefile) + { + chomp($codefile[$e]); + if ($codefile[$e] =~ /^$match_code\t/) + { + @m = split(/\t/, $codefile[$e]); + $area_code = $m[2]; + $area_state = $m[3]; + $area_GMT = $m[4]; $area_GMT =~ s/\+//gi; $area_GMT = ($area_GMT + 0); + $area_GMT_method = $m[6]; + if ($area_code =~ /S/) # look for state override flag in areacode field + { + $area_code =~ s/\D//gi; + $AC_match = " and phone_number LIKE \"$area_code%\" and state='$area_state'"; + if ($DB) {print " AREA CODE STATE OVERRIDE: $codefile[$e]\n";} + } + else + { + if ($area_code =~ /\*/) {$AC_match = '';} + else {$AC_match = " and phone_number LIKE \"$area_code%\"";} + } + if ($DBX) {print "PROCESSING THIS LINE: $codefile[$e]\n";} + $stmtA = "select count(*) from vicidial_list where phone_code='$match_code_ORIG' $AC_match;"; + if($DBX){print STDERR "\n|$stmtA|\n";} + $dbhA->query($stmtA); + $rec_countZ=0; + if ($dbhA->has_selected_record) + { + $iterA=$dbhA->create_record_iterator; + while ($recordA = $iterA->each) + { + $rec_countZ = $recordA->[0]; + } + } + if (!$rec_countZ) + { + if ($DB) {print " IGNORING: $codefile[$e]\n";} + $ei++; + } + else + { + $AC_GMT_diff = ($area_GMT - $LOCAL_GMT_OFF_STD); + $AC_localtime = ($secX + (3600 * $AC_GMT_diff)); + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($AC_localtime); + $year = ($year + 1900); + $mon++; + if ($mon < 10) {$mon = "0$mon";} + if ($mday < 10) {$mday = "0$mday";} + if ($hour < 10) {$hour = "0$hour";} + if ($min < 10) {$min = "0$min";} + if ($sec < 10) {$sec = "0$sec";} + $dsec = ( ( ($hour * 3600) + ($min * 60) ) + $sec ); + + $AC_processed=0; + if ( (!$AC_processed) && ($area_GMT_method =~ /FSA-LSO/) ) + { + if ($DBX) {print " First Sunday April to Last Sunday October\n";} + &USA_dstcalc; + if ($DBX) {print " DST: $USA_DST\n";} + if ($USA_DST) {$area_GMT++;} + $AC_processed++; + } + if ( (!$AC_processed) && ($area_GMT_method =~ /LSM-LSO/) ) + { + if ($DBX) {print " Last Sunday March to Last Sunday October\n";} + &GBR_dstcalc; + if ($DBX) {print " DST: $GBR_DST\n";} + if ($GBR_DST) {$area_GMT++;} + $AC_processed++; + } + if ( (!$AC_processed) && ($area_GMT_method =~ /LSO-LSM/) ) + { + if ($DBX) {print " Last Sunday October to Last Sunday March\n";} + &AUS_dstcalc; + if ($DBX) {print " DST: $AUS_DST\n";} + if ($AUS_DST) {$area_GMT++;} + $AC_processed++; + } + if ( (!$AC_processed) && ($area_GMT_method =~ /FSO-LSM/) ) + { + if ($DBX) {print " First Sunday October to Last Sunday March\n";} + &AUST_dstcalc; + if ($DBX) {print " DST: $AUST_DST\n";} + if ($AUST_DST) {$area_GMT++;} + $AC_processed++; + } + if ( (!$AC_processed) && ($area_GMT_method =~ /FSO-TSM/) ) + { + if ($DBX) {print " First Sunday October to Third Sunday March\n";} + &NZL_dstcalc; + if ($DBX) {print " DST: $NZL_DST\n";} + if ($NZL_DST) {$area_GMT++;} + $AC_processed++; + } + if (!$AC_processed) + { + if ($DBX) {print " No DST Method Found\n";} + if ($DBX) {print " DST: 0\n";} + $AC_processed++; + } + + + if ($AC_processed) + { + $stmtA = "select count(*) from vicidial_list where phone_code='$match_code_ORIG' $AC_match and gmt_offset_now != '$area_GMT';"; + if($DBX){print STDERR "\n|$stmtA|\n";} + $dbhA->query($stmtA); + $rec_countW=0; + if ($dbhA->has_selected_record) + { + $iterA=$dbhA->create_record_iterator; + while ($recordA = $iterA->each) + { + $rec_countW = $recordA->[0]; + } + } + if (!$rec_countW) + { + if ($DB) {print " ALL GMT ALREADY CORRECT FOR : $match_code_ORIG $area_code $area_GMT\n";} + $ei++; + } + else + { + $stmtA = "update vicidial_list set gmt_offset_now='$area_GMT' where phone_code='$match_code_ORIG' $AC_match and gmt_offset_now != '$area_GMT';"; + if($DB){print STDERR "\n|$stmtA|\n";} + if (!$T) {$dbhA->query($stmtA); } + $Prec_countW = sprintf("%8s", $rec_countW); + if ($DB) {print " $Prec_countW records in $match_code_ORIG $area_code updated to $area_GMT\n";} + $ee++; + # sleep(1); + } + } + } + + $ep++; + } + else + { + if ($DBX) {print " IGNORING: $codefile[$e]\n";} + $ei++; + } + $e++; + } + + $d++; + } + + + + $dbhA->close; + +if($DB){print "\nDONE\n";} + +exit; + + + + +sub USA_dstcalc { +#********************************************************************** +# FSA-LSO +# This is returns 1 if Daylight Savings Time is in effect and 0 if +# Standard time is in effect. +# Based on first Sunday in April and last Sunday in October at 2 am. +# INPUTS: +# mm INTEGER Month. +# dd INTEGER Day of the month. +# ns INTEGER Seconds into the day. +# dow INTEGER Day of week (0=Sunday, to 6=Saturday) +# OPTIONAL INPUT: +# timezone INTEGER hour difference UTC - local standard time +# (DEFAULT is blank) +# make calculations based on UTC time, +# which means shift at 10:00 UTC in April +# and 9:00 UTC in October +# OUTPUT: +# INTEGER 1 = DST, 0 = not DST +#********************************************************************** + + $USA_DST=0; + $mm = $mon; + $dd = $mday; + $ns = $dsec; + $dow= $wday; + + if ($mm < 4 || $mm > 10) { + $USA_DST=0; return 0; + } elsif ($mm >= 5 && $mm <= 9) { + $USA_DST=1; return 1; + } elsif ($mm == 4) { + if ($dd > 7) { + $USA_DST=1; return 1; + } elsif ($dd >= ($dow+1)) { + if ($timezone) { + if ($dow == 0 && $ns < (7200+$timezone*3600)) { + $USA_DST=0; return 0; + } else { + $USA_DST=1; return 1; + } + } else { + if ($dow == 0 && $ns < 7200) { + $USA_DST=0; return 0; + } else { + $USA_DST=1; return 1; + } + } + } else { + $USA_DST=0; return 0; + } + } elsif ($mm == 10) { + if ($dd < 25) { + $USA_DST=1; return 1; + } elsif ($dd < ($dow+25)) { + $USA_DST=1; return 1; + } elsif ($dow == 0) { + if ($timezone) { # UTC calculations + if ($ns < (7200+($timezone-1)*3600)) { + $USA_DST=1; return 1; + } else { + $USA_DST=0; return 0; + } + } else { # local time calculations + if ($ns < 7200) { + $USA_DST=1; return 1; + } else { + $USA_DST=0; return 0; + } + } + } else { + $USA_DST=0; return 0; + } + } # end of month checks +} # end of subroutine dstcalc + + + + +sub GBR_dstcalc { +#********************************************************************** +# This is returns 1 if Daylight Savings Time is in effect and 0 if +# Standard time is in effect. +# Based on last Sunday in March and last Sunday in October at 1 am. +#********************************************************************** + + $GBR_DST=0; + $mm = $mon; + $dd = $mday; + $ns = $dsec; + $dow= $wday; + + if ($mm < 3 || $mm > 10) { + $GBR_DST=0; return 0; + } elsif ($mm >= 4 && $mm <= 9) { + $GBR_DST=1; return 1; + } elsif ($mm == 3) { + if ($dd < 25) { + $GBR_DST=0; return 0; + } elsif ($dd < ($dow+25)) { + $GBR_DST=0; return 0; + } elsif ($dow == 0) { + if ($timezone) { # UTC calculations + if ($ns < (3600+($timezone-1)*3600)) { + $GBR_DST=0; return 0; + } else { + $GBR_DST=1; return 1; + } + } else { # local time calculations + if ($ns < 3600) { + $GBR_DST=0; return 0; + } else { + $GBR_DST=1; return 1; + } + } + } else { + $GBR_DST=1; return 1; + } + } elsif ($mm == 10) { + if ($dd < 25) { + $GBR_DST=1; return 1; + } elsif ($dd < ($dow+25)) { + $GBR_DST=1; return 1; + } elsif ($dow == 0) { + if ($timezone) { # UTC calculations + if ($ns < (3600+($timezone-1)*3600)) { + $GBR_DST=1; return 1; + } else { + $GBR_DST=0; return 0; + } + } else { # local time calculations + if ($ns < 3600) { + $GBR_DST=1; return 1; + } else { + $GBR_DST=0; return 0; + } + } + } else { + $GBR_DST=0; return 0; + } + } # end of month checks +} # end of subroutine dstcalc + + + + +sub AUS_dstcalc { +#********************************************************************** +# This is returns 1 if Daylight Savings Time is in effect and 0 if +# Standard time is in effect. +# Based on last Sunday in October and last Sunday in March at 1 am. +#********************************************************************** + + $AUS_DST=0; + $mm = $mon; + $dd = $mday; + $ns = $dsec; + $dow= $wday; + + if ($mm < 3 || $mm > 10) { + $AUS_DST=1; return 1; + } elsif ($mm >= 4 && $mm <= 9) { + $AUS_DST=0; return 0; + } elsif ($mm == 3) { + if ($dd < 25) { + $AUS_DST=1; return 1; + } elsif ($dd < ($dow+25)) { + $AUS_DST=1; return 1; + } elsif ($dow == 0) { + if ($timezone) { # UTC calculations + if ($ns < (3600+($timezone-1)*3600)) { + $AUS_DST=1; return 1; + } else { + $AUS_DST=0; return 0; + } + } else { # local time calculations + if ($ns < 3600) { + $AUS_DST=1; return 1; + } else { + $AUS_DST=0; return 0; + } + } + } else { + $AUS_DST=0; return 0; + } + } elsif ($mm == 10) { + if ($dd < 25) { + $AUS_DST=0; return 0; + } elsif ($dd < ($dow+25)) { + $AUS_DST=0; return 0; + } elsif ($dow == 0) { + if ($timezone) { # UTC calculations + if ($ns < (3600+($timezone-1)*3600)) { + $AUS_DST=0; return 0; + } else { + $AUS_DST=1; return 1; + } + } else { # local time calculations + if ($ns < 3600) { + $AUS_DST=0; return 0; + } else { + $AUS_DST=1; return 1; + } + } + } else { + $AUS_DST=1; return 1; + } + } # end of month checks +} # end of subroutine dstcalc + + + + + +sub AUST_dstcalc { +#********************************************************************** +# TASMANIA ONLY +# This is returns 1 if Daylight Savings Time is in effect and 0 if +# Standard time is in effect. +# Based on first Sunday in October and last Sunday in March at 1 am. +#********************************************************************** + + $AUST_DST=0; + $mm = $mon; + $dd = $mday; + $ns = $dsec; + $dow= $wday; + + if ($mm < 3 || $mm > 10) { + $AUST_DST=1; return 1; + } elsif ($mm >= 4 && $mm <= 9) { + $AUST_DST=0; return 0; + } elsif ($mm == 3) { + if ($dd < 25) { + $AUST_DST=1; return 1; + } elsif ($dd < ($dow+25)) { + $AUST_DST=1; return 1; + } elsif ($dow == 0) { + if ($timezone) { # UTC calculations + if ($ns < (3600+($timezone-1)*3600)) { + $AUST_DST=1; return 1; + } else { + $AUST_DST=0; return 0; + } + } else { # local time calculations + if ($ns < 3600) { + $AUST_DST=1; return 1; + } else { + $AUST_DST=0; return 0; + } + } + } else { + $AUST_DST=0; return 0; + } + } elsif ($mm == 10) { + if ($dd > 7) { + $AUST_DST=1; return 1; + } elsif ($dd >= ($dow+1)) { + if ($timezone) { + if ($dow == 0 && $ns < (7200+$timezone*3600)) { + $AUST_DST=0; return 0; + } else { + $AUST_DST=1; return 1; + } + } else { + if ($dow == 0 && $ns < 3600) { + $AUST_DST=0; return 0; + } else { + $AUST_DST=1; return 1; + } + } + } else { + $AUST_DST=0; return 0; + } + } # end of month checks +} # end of subroutine dstcalc + + + + + +sub NZL_dstcalc { +#********************************************************************** +# This is returns 1 if Daylight Savings Time is in effect and 0 if +# Standard time is in effect. +# Based on first Sunday in October and third Sunday in March at 1 am. +#********************************************************************** + + $NZL_DST=0; + $mm = $mon; + $dd = $mday; + $ns = $dsec; + $dow= $wday; + + if ($mm < 3 || $mm > 10) { + $NZL_DST=1; return 1; + } elsif ($mm >= 4 && $mm <= 9) { + $NZL_DST=0; return 0; + } elsif ($mm == 3) { + if ($dd < 14) { + $NZL_DST=1; return 1; + } elsif ($dd < ($dow+14)) { + $NZL_DST=1; return 1; + } elsif ($dow == 0) { + if ($timezone) { # UTC calculations + if ($ns < (3600+($timezone-1)*3600)) { + $NZL_DST=1; return 1; + } else { + $NZL_DST=0; return 0; + } + } else { # local time calculations + if ($ns < 3600) { + $NZL_DST=1; return 1; + } else { + $NZL_DST=0; return 0; + } + } + } else { + $NZL_DST=0; return 0; + } + } elsif ($mm == 10) { + if ($dd > 7) { + $NZL_DST=1; return 1; + } elsif ($dd >= ($dow+1)) { + if ($timezone) { + if ($dow == 0 && $ns < (7200+$timezone*3600)) { + $NZL_DST=0; return 0; + } else { + $NZL_DST=1; return 1; + } + } else { + if ($dow == 0 && $ns < 3600) { + $NZL_DST=0; return 0; + } else { + $NZL_DST=1; return 1; + } + } + } else { + $NZL_DST=0; return 0; + } + } # end of month checks +} # end of subroutine dstcalc diff --git a/ADMIN_area_code_populate.pl b/ADMIN_area_code_populate.pl new file mode 100644 index 00000000..1bbc129c --- /dev/null +++ b/ADMIN_area_code_populate.pl @@ -0,0 +1,67 @@ +#!/usr/bin/perl +# ADMIN_area_code_populate.pl version 1.1.12 for Perl +# +# Copyright (C) 2006 Joe Johnson,Matt Florell LICENSE: GPLv2 +# +# Description: +# server application that allows load areacodes into to asterisk list database +# +# +# CHANGES +# 60615-1514 - Changed to ignore the header row +# + +use lib ".\\",".\\libs", './', './libs', '../libs', '/usr/local/perl_TK/libs', 'C:\\AST_VICI\\libs'; +use Time::HiRes ('gettimeofday','usleep','sleep'); # needed to have perl sleep in increments of less than one second +use Net::MySQL; + +### Make sure this file is in a libs path or put the absolute path to it +require("/home/cron/AST_SERVER_conf.pl"); # local configuration file + +if (!$DB_port) {$DB_port='3306';} + +$dbh = Net::MySQL->new(hostname => "$DB_server", database => "$DB_database", user => "$DB_user", password => "$DB_pass", port => "$DB_port") + or die "Couldn't connect to database: $DB_server - $DB_database\n"; + + +$slash_star = '\*'; + + open(codefile, "/home/cron/phone_codes_GMT.txt") || die "can't open /home/cron/phone_codes_GMT.txt: $!\n"; + @codefile = ; + close(codefile); + $pc=0; + $ins_stmt="insert into vicidial_phone_codes VALUES "; + foreach (@codefile) + { + @row=split(/\t/, $codefile[$pc]); + if ($codefile[$pc] !~ /GEOGRAPHIC DESCRIPTION/) + { + $pc++; + $row[7] =~ s/\r|\n|\t| $//gi; + $row[6] =~ s/\r|\n|\t| $//gi; + $row[5] =~ s/\r|\n|\t| $//gi; + $row[4] =~ s/\r|\n|\t| $//gi; + $row[3] =~ s/\r|\n|\t| $//gi; + $row[2] =~ s/\r|\n|\t| $//gi; + $row[1] =~ s/\r|\n|\t| $//gi; + $row[0] =~ s/\r|\n|\t| $//gi; + $ins_stmt.="('$row[0]', '$row[1]', '$row[2]', '$row[3]', '$row[4]', '$row[5]', '$row[6]', '$row[7]'), "; + if ($pc =~ /00$/) + { + chop($ins_stmt); + chop($ins_stmt); + $dbh->query($ins_stmt) || die "can't execute query: |$ins_stmt| $!\n"; + $ins_stmt="insert into vicidial_phone_codes VALUES "; + print STDERR "$pc\n"; + } + } + else {$pc++;} + } + + chop($ins_stmt); + chop($ins_stmt); + $dbh->query($ins_stmt); + $ins_stmt="insert into vicidial_phone_codes VALUES "; + print STDERR "$pc\n"; + +exit; \ No newline at end of file diff --git a/ADMIN_keepalive_AST_VDautodial.pl b/ADMIN_keepalive_AST_VDautodial.pl new file mode 100644 index 00000000..b40027f7 --- /dev/null +++ b/ADMIN_keepalive_AST_VDautodial.pl @@ -0,0 +1,120 @@ +#!/usr/bin/perl +# +# ADMIN_keepalive_AST_VDauto_dial.pl version 0.3 +# +# designed to keep the AST_update processes aline and check every minute +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# +# +# 50810-1452 - removed '-L' flag for screen logging of output (optimization) +# 50823-1454 - Added commandline debug options with debug printouts +# + +$DB=0; # Debug flag +$MT[0]=''; $MT[1]=''; +@psline=@MT; + +### begin parsing run-time options ### +if (length($ARGV[0])>1) +{ + $i=0; + while ($#ARGV >= $i) + { + $args = "$args $ARGV[$i]"; + $i++; + } + + if ($args =~ /--help/i) + { + print "allowed run time options:\n [-t] = test\n [-debug] = verbose debug messages\n[-debugX] = Extra-verbose debug messages\n\n"; + } + else + { + if ($args =~ /-debug/i) + { + $DB=1; # Debug flag + } + if ($args =~ /--debugX/i) + { + $DBX=1; + print "\n----- SUPER-DUPER DEBUGGING -----\n\n"; + } + if ($args =~ /-t/i) + { + $TEST=1; + $T=1; + } + } +} +else +{ +# print "no command line options set\n"; +} +### end parsing run-time options ### + + +#@psoutput = `ps -f -C AST_update --no-headers`; +#@psoutput = `ps -f -C AST_updat* --no-headers`; +#@psoutput = `/bin/ps -f --no-headers -A`; +@psoutput = `/bin/ps -o "%p %a" --no-headers -A`; + +$running_VDAD = 0; + +$i=0; +foreach (@psoutput) +{ + chomp($psoutput[$i]); +if ($DBX) {print "$i|$psoutput[$i]| \n";} +@psline = split(/\/usr\/bin\/perl /,$psoutput[$i]); + +if ($psline[1] =~ /\/home\/cron\/AST_VDauto_dial\.pl/) + { + $running_VDAD++; + if ($DB) {print "VDAD RUNNING: |$psline[1]|\n";} + } + +$i++; +} + + +if (!$running_VDAD) +{ +# print "double check that VDAD is not running\n"; + + sleep(4); + +#@psoutput = `ps -f -C AST_update --no-headers`; +#@psoutput = `ps -f -C AST_updat* --no-headers`; +#@psoutput = `/bin/ps -f --no-headers -A`; +@psoutput = `/bin/ps -o "%p %a" --no-headers -A`; +$i=0; +foreach (@psoutput2) + { + chomp($psoutput2[$i]); + if ($DBX) {print "$i|$psoutput[$i]| \n";} + @psline = split(/\/usr\/bin\/perl /,$psoutput2[$i]); + + if ($psline[1] =~ /\/home\/cron\/AST_VDauto_dial\.pl/) + { + $running_VDAD++; + if ($DB) {print "VDAD RUNNING: |$psline[1]|\n";} + } + + $i++; + } + +if (!$running_VDAD) + { + if ($DB) {print "starting AST_VDauto_dial...\n";} + # add a '-L' to the command below to activate logging + `/usr/bin/screen -d -m -S ASTVDauto /home/cron/AST_VDauto_dial.pl`; + } +} + + + + + if ($DB) {print "DONE\n";} + +exit; diff --git a/ADMIN_keepalive_AST_VDremote_agents.pl b/ADMIN_keepalive_AST_VDremote_agents.pl new file mode 100644 index 00000000..5b834222 --- /dev/null +++ b/ADMIN_keepalive_AST_VDremote_agents.pl @@ -0,0 +1,119 @@ +#!/usr/bin/perl +# +# ADMIN_keepalive_AST_VDremote_agents.pl version 0.3 +# +# designed to keep the AST_update processes aline and check every minute +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# +# +# 50810-1453 - removed '-L' flag for screen logging of output (optimization) +# 50823-1459 - Added commandline debug options with debug printouts +# + +$DB=0; # Debug flag +$MT[0]=''; $MT[1]=''; +@psline=@MT; + +### begin parsing run-time options ### +if (length($ARGV[0])>1) +{ + $i=0; + while ($#ARGV >= $i) + { + $args = "$args $ARGV[$i]"; + $i++; + } + + if ($args =~ /--help/i) + { + print "allowed run time options:\n [-t] = test\n [-debug] = verbose debug messages\n[-debugX] = Extra-verbose debug messages\n\n"; + } + else + { + if ($args =~ /-debug/i) + { + $DB=1; # Debug flag + } + if ($args =~ /--debugX/i) + { + $DBX=1; + print "\n----- SUPER-DUPER DEBUGGING -----\n\n"; + } + if ($args =~ /-t/i) + { + $TEST=1; + $T=1; + } + } +} +else +{ +# print "no command line options set\n"; +} +### end parsing run-time options ### + +#@psoutput = `ps -f -C AST_update --no-headers`; +#@psoutput = `ps -f -C AST_updat* --no-headers`; +#@psoutput = `/bin/ps -f --no-headers -A`; +@psoutput = `/bin/ps -o "%p %a" --no-headers -A`; + +$running_VDra = 0; + +$i=0; +foreach (@psoutput) +{ + chomp($psoutput[$i]); +if ($DBX) {print "$i|$psoutput[$i]| \n";} +@psline = split(/\/usr\/bin\/perl /,$psoutput[$i]); + +if ($psline[1] =~ /\/home\/cron\/AST_VDremote_agents\.pl/) + { + $running_VDra++; + if ($DB) {print "VDra RUNNING: |$psline[1]|\n";} + } + +$i++; +} + + +if (!$running_VDra) +{ +# print "double check that update is not running\n"; + + sleep(5); + +#@psoutput = `ps -f -C AST_update --no-headers`; +#@psoutput = `ps -f -C AST_updat* --no-headers`; +#@psoutput = `/bin/ps -f --no-headers -A`; +@psoutput = `/bin/ps -o "%p %a" --no-headers -A`; +$i=0; +foreach (@psoutput2) + { + chomp($psoutput2[$i]); + if ($DBX) {print "$i|$psoutput[$i]| \n";} + @psline = split(/\/usr\/bin\/perl /,$psoutput2[$i]); + + if ($psline[1] =~ /\/home\/cron\/AST_VDremote_agents\.pl/) + { + $running_VDra++; + if ($DB) {print "VDra RUNNING: |$psline[1]|\n";} + } + + $i++; + } + +if (!$running_VDra) + { + if ($DB) {print "starting AST_VDremote_agents...\n";} + # add a '-L' to the command below to activate logging + `/usr/bin/screen -d -m -S ASTVDremote /home/cron/AST_VDremote_agents.pl`; + } +} + + + + + if ($DB) {print "DONE\n";} + +exit; diff --git a/ADMIN_keepalive_AST_send_listen.pl b/ADMIN_keepalive_AST_send_listen.pl new file mode 100644 index 00000000..bdf94ead --- /dev/null +++ b/ADMIN_keepalive_AST_send_listen.pl @@ -0,0 +1,169 @@ +#!/usr/bin/perl +# +# ADMIN_keepalive_AST_send_listen.pl version 0.3 +# +# designed to keep the AST_manager_listen and manager_send processes alive and check every minute +# +# if you are on an older system you may need to change the @psoutput lines to fit your ps version +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# +# +# 50810-1450 - removed '-L' flag for screen logging of output (optimization) +# 50823-1440 - Added commandline debug options with debug printouts +# + +$DB=0; # Debug flag +$MT[0]=''; $MT[1]=''; +@psline=@MT; + +### begin parsing run-time options ### +if (length($ARGV[0])>1) +{ + $i=0; + while ($#ARGV >= $i) + { + $args = "$args $ARGV[$i]"; + $i++; + } + + if ($args =~ /--help/i) + { + print "allowed run time options:\n [-t] = test\n [-debug] = verbose debug messages\n[-debugX] = Extra-verbose debug messages\n\n"; + } + else + { + if ($args =~ /-debug/i) + { + $DB=1; # Debug flag + } + if ($args =~ /--debugX/i) + { + $DBX=1; + print "\n----- SUPER-DUPER DEBUGGING -----\n\n"; + } + if ($args =~ /-t/i) + { + $TEST=1; + $T=1; + } + } +} +else +{ +# print "no command line options set\n"; +} +### end parsing run-time options ### + + sleep(1); + + +#@psoutput = `ps -f -C AST_manager --no-headers`; +#@psoutput = `ps -f --no-headers -C AST_manager_s*; ps -f --no-headers -C AST_manager_l*`; +#@psoutput = `/bin/ps -f --no-headers -A`; +@psoutput = `/bin/ps -o "%p %a" --no-headers -A`; + +$running_listen = 0; +$running_send = 0; + +$i=0; +foreach (@psoutput) +{ + chomp($psoutput[$i]); +if ($DBX) {print "$i|$psoutput[$i]| \n";} +@psline = split(/\/usr\/bin\/perl /,$psoutput[$i]); + +if ($psline[1] =~ /AST_manager_li/) + { + $running_listen++; + if ($DB) {print "LISTEN RUNNING: |$psline[1]|\n";} + } +if ($psline[1] =~ /AST_manager_se/) + { + $running_send++; + if ($DB) {print "SEND RUNNING: |$psline[1]|\n";} + } + +$i++; +} + + + +if (!$running_listen) +{ + # print "double check that update_11 is not running\n"; + + sleep(1); + +#@psoutput = `ps -f -C AST_manager --no-headers`; +#@psoutput = `ps -f --no-headers -C AST_manager_s*; ps -f --no-headers -C AST_manager_l*`; +#@psoutput = `/bin/ps -f --no-headers -A`; +@psoutput = `/bin/ps -o "%p %a" --no-headers -A`; + +$i=0; +foreach (@psoutput2) + { + chomp($psoutput2[$i]); + if ($DBX) {print "$i|$psoutput[$i]| \n";} + @psline = split(/\/usr\/bin\/perl /,$psoutput2[$i]); + + if ($psline[1] =~ /AST_manager_li/) + { + $running_listen++; + if ($DB) {print "LISTEN RUNNING: |$psline[1]|\n";} + } + + $i++; + } + +if (!$running_listen) + { + if ($DB) {print "starting AST_manager_listen...\n";} + # add a '-L' to the command below to activate logging + `/usr/bin/screen -d -m -S ASTlisten /home/cron/AST_manager_listen.pl`; + } +} + + + + +if (!$running_send) +{ + # print "double check that update_12 is not running\n"; + + sleep(1); + +#@psoutput = `ps -f -C AST_manager --no-headers`; +#@psoutput = `ps -f --no-headers -C AST_manager_s*; ps -f --no-headers -C AST_manager_l*`; +#@psoutput = `/bin/ps -f --no-headers -A`; +@psoutput = `/bin/ps -o "%p %a" --no-headers -A`; +$i=0; +foreach (@psoutput) + { + chomp($psoutput[$i]); + if ($DBX) {print "$i|$psoutput[$i]| \n";} + @psline = split(/\/usr\/bin\/perl /,$psoutput[$i]); + + if ($psline[1] =~ /AST_manager_se/) + { + $running_send++; + if ($DB) {print "SEND RUNNING: |$psline[1]|";} + } + + $i++; + } + +if (!$running_send) + { + if ($DB) {print "starting AST_manager_send...\n";} + # add a '-L' to the command below to activate logging + `/usr/bin/screen -d -m -S ASTsend /home/cron/AST_manager_send.pl`; + } +} + + + + + if ($DB) {print "DONE\n";} + +exit; diff --git a/ADMIN_keepalive_AST_update.pl b/ADMIN_keepalive_AST_update.pl new file mode 100644 index 00000000..4a713e30 --- /dev/null +++ b/ADMIN_keepalive_AST_update.pl @@ -0,0 +1,121 @@ +#!/usr/bin/perl +# +# ADMIN_keepalive_AST_update.pl version 0.4 +# +# designed to keep the AST_update processes aline and check every minute +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# +# +# 50810-1451 - removed '-L' flag for screen logging of output (optimization) +# 50823-1446 - Added commandline debug options with debug printouts +# 51229-1027 - fixed typo of array name +# + +$DB=0; # Debug flag +$MT[0]=''; $MT[1]=''; +@psline=@MT; + +### begin parsing run-time options ### +if (length($ARGV[0])>1) +{ + $i=0; + while ($#ARGV >= $i) + { + $args = "$args $ARGV[$i]"; + $i++; + } + + if ($args =~ /--help/i) + { + print "allowed run time options:\n [-t] = test\n [-debug] = verbose debug messages\n[-debugX] = Extra-verbose debug messages\n\n"; + } + else + { + if ($args =~ /-debug/i) + { + $DB=1; # Debug flag + } + if ($args =~ /--debugX/i) + { + $DBX=1; + print "\n----- SUPER-DUPER DEBUGGING -----\n\n"; + } + if ($args =~ /-t/i) + { + $TEST=1; + $T=1; + } + } +} +else +{ +# print "no command line options set\n"; +} +### end parsing run-time options ### + + +#@psoutput = `ps -f -C AST_update --no-headers`; +#@psoutput = `ps -f -C AST_updat* --no-headers`; +#@psoutput = `/bin/ps -f --no-headers -A`; +@psoutput = `/bin/ps -o "%p %a" --no-headers -A`; + +$running_update = 0; + +$i=0; +foreach (@psoutput) +{ + chomp($psoutput[$i]); +if ($DBX) {print "$i|$psoutput[$i]| \n";} +@psline = split(/\/usr\/bin\/perl /,$psoutput[$i]); + +if ($psline[1] =~ /\/home\/cron\/AST_update\.pl/) + { + $running_update++; + if ($DB) {print "UPDATE RUNNING: |$psline[1]|\n";} + } + +$i++; +} + + +if (!$running_update) +{ +# print "double check that update is not running\n"; + + sleep(5); + +#@psoutput = `ps -f -C AST_update --no-headers`; +#@psoutput = `ps -f -C AST_updat* --no-headers`; +#@psoutput = `/bin/ps -f --no-headers -A`; +@psoutput2 = `/bin/ps -o "%p %a" --no-headers -A`; +$i=0; +foreach (@psoutput2) + { + chomp($psoutput2[$i]); + if ($DBX) {print "$i|$psoutput[$i]| \n";} + @psline = split(/\/usr\/bin\/perl /,$psoutput2[$i]); + + if ($psline[1] =~ /\/home\/cron\/AST_update\.pl/) + { + $running_update++; + if ($DB) {print "UPDATE RUNNING: |$psline[1]|\n";} + } + + $i++; + } + +if (!$running_update) + { + if ($DB) {print "starting AST_update...\n";} + # add a '-L' to the command below to activate logging + `/usr/bin/screen -d -m -S ASTupdate /home/cron/AST_update.pl`; + } +} + + + + + if ($DB) {print "DONE\n";} + +exit; diff --git a/ADMIN_keepalive_send_listen.at b/ADMIN_keepalive_send_listen.at new file mode 100644 index 00000000..652c1bc0 --- /dev/null +++ b/ADMIN_keepalive_send_listen.at @@ -0,0 +1,6 @@ +#!/bin/sh + +/home/cron/ADMIN_keepalive_AST_send_listen.pl + +exit + diff --git a/ADMIN_restart_roll_logs.pl b/ADMIN_restart_roll_logs.pl new file mode 100644 index 00000000..a617e3da --- /dev/null +++ b/ADMIN_restart_roll_logs.pl @@ -0,0 +1,52 @@ +#!/usr/bin/perl +# ADMIN_restart_roll_logs.pl - script to roll the Asterisk logs on machine restart +# have this run on the astersik server +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# + +($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); +$year = ($year + 1900); +$mon++; +if ($mon < 10) {$mon = "0$mon";} +if ($mday < 10) {$mday = "0$mday";} +if ($hour < 10) {$Fhour = "0$hour";} +if ($min < 10) {$min = "0$min";} +if ($sec < 10) {$sec = "0$sec";} + +$now_date_epoch = time(); +$now_date = "$year-$mon-$mday---$hour$min$sec"; + + +print "rolling AST_update log...\n"; +`mv -f /home/cron/LOG_AST_update.log /home/cron/LOGS/LOG_AST_update.log.$now_date`; + +print "rolling MSAST_update log...\n"; +`mv -f /home/cron/MSLOG_AST_update.log /home/cron/LOGS/MSLOG_AST_update.log.$now_date`; + +print "rolling LIAST_update log...\n"; +`mv -f /home/cron/LILOG_AST_update.log /home/cron/LOGS/LILOG_AST_update.log.$now_date`; + +print "rolling VDAST_update log...\n"; +`mv -f /home/cron/VDLOG_AST_update.log /home/cron/LOGS/VDLOG_AST_update.log.$now_date`; + +print "rolling Asterisk messages log...\n"; +`mv -f /var/log/asterisk/messages /var/log/asterisk/messages.$now_date`; + +print "rolling Asterisk event log...\n"; +`mv -f /var/log/asterisk/event_log /var/log/asterisk/event_log.$now_date`; + +print "rolling Asterisk cdr logs...\n"; +`mv -f /var/log/asterisk/cdr-csv/Master.csv /var/log/asterisk/cdr-csv/Master.csv.$now_date`; +`mv -f /var/log/asterisk/cdr-custom/Master.csv /var/log/asterisk/cdr-custom/Master.csv.$now_date`; + +print "rolling Asterisk screen log...\n"; +`mv -f /screenlog.0 /screenlog.0.$now_date`; + +print "rolling Asterisk root screen log...\n"; +`mv -f /root/screenlog.0 /root/screenlog.0.$now_date`; + + +print "FINISHED... EXITING\n"; + +exit; diff --git a/AST_CRON_mix_recordings.pl b/AST_CRON_mix_recordings.pl new file mode 100644 index 00000000..f14198e3 --- /dev/null +++ b/AST_CRON_mix_recordings.pl @@ -0,0 +1,124 @@ +#!/usr/bin/perl +# +# AST_CRON_mix_recordings.pl +# runs every 5 minutes and mixes the call recordings in the monitor together +# and puts the resulting ALL file into the DONE directory in the "monitor" dir +# +# soxmix is REQUIRED to use this script, soxmix is available only as part of +# the sox audio package, and only in newer versions. Make sure you have soxmix +# installed properly and in your path +# +# put an entry into the cron of of your asterisk machine to run this script +# every 5 minutes or however often you desire +# +# make sure that the following directories exist: +# /var/spool/asterisk/monitor # default Asterisk recording directory +# /var/spool/asterisk/monitor/DONE # where the combined files are put +# /var/spool/asterisk/monitor/ORIG # where the original in/out files are put +# +# This program assumes that recordings are saved as .wav +# should be easy to change this code if you use .gsm instead +# +# This program also sends the ALL combined file to an FTP server for archival +# purposes, you can comment out the Net::Ping and Net::FTP lines as well as the +# file transfer section of the code to deactivate remote copying of the +# recording files +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# +# +# 51021-1058 Added quotes around CLI executed commands +# 51122-1458 Added soxmix binary path check +# 60318-0921 Added ability to mix gsm audio files +# + + +#$v=1; + +# Customize variables for FTP +$FTP_host = '10.0.0.4'; +$FTP_user = 'cron'; +$FTP_pass = 'test'; +$FTP_dir = 'RECORDINGS'; + +### directory where in/out recordings are saved to by Asterisk +$dir1 = '/var/spool/asterisk/monitor'; + +$soxmixbin = ''; +if ( -e ('/usr/bin/soxmix')) {$soxmixbin = '/usr/bin/soxmix';} +else + { + if ( -e ('/usr/local/bin/soxmix')) {$soxmixbin = '/usr/local/bin/soxmix';} + else + { + print "Can't find soxmix binary! Exiting...\n"; + exit; + } + } + +use Net::Ping; +use Net::FTP; + + + opendir(FILE, "$dir1/"); + @FILES = readdir(FILE); + +$i=0; +foreach(@FILES) + { + $size1 = 0; + $size2 = 0; + + if ( (length($FILES[$i]) > 4) && (!-d $FILES[$i]) ) + { + + $size1 = (-s "$dir1/$FILES[$i]"); + if ($v) {print "$FILES[$i] $size1\n";} + sleep(1); + $size2 = (-s "$dir1/$FILES[$i]"); + if ($v) {print "$FILES[$i] $size2\n\n";} + + if ( ($FILES[$i] !~ /out\.wav|out\.gsm/i) && ($size1 eq $size2) && (length($FILES[$i]) > 4)) + { + $INfile = $FILES[$i]; + $OUTfile = $FILES[$i]; + $OUTfile =~ s/-in\.wav/-out.wav/gi; + $OUTfile =~ s/-in\.gsm/-out.gsm/gi; + $ALLfile = $FILES[$i]; + $ALLfile =~ s/-in\.wav/-all.wav/gi; + $ALLfile =~ s/-in\.gsm/-all.gsm/gi; + + if ($v) {print "|$INfile| |$OUTfile| |$ALLfile|\n\n";} + + `$soxmixbin "$dir1/$INfile" "$dir1/$OUTfile" "$dir1/$ALLfile"`; + if ($v) {print "|$INfile| |$OUTfile| |$ALLfile|\n\n";} + if (!$T) + { + `mv -f "$dir1/$INfile" "$dir1/ORIG/$INfile"`; + `mv -f "$dir1/$OUTfile" "$dir1/ORIG/$OUTfile"`; + `mv -f "$dir1/$ALLfile" "$dir1/DONE/$ALLfile"`; + } + + ### BEGIN Remote file transfer + $p = Net::Ping->new(); + $ping_good = $p->ping("$FTP_host"); + + if ($ping_good) + { + $ftp = Net::FTP->new("$FTP_host", Port => 21); + $ftp->login("$FTP_user","$FTP_pass"); + $ftp->cwd("$FTP_dir"); + $ftp->binary(); + $ftp->put("$dir1/DONE/$ALLfile", "$ALLfile"); + $ftp->quit; + } + ### END Remote file transfer + + } + } + $i++; + } + +if ($v) {print "DONE... EXITING\n\n";} + +exit; diff --git a/AST_CRON_mix_recordings_BASIC.pl b/AST_CRON_mix_recordings_BASIC.pl new file mode 100644 index 00000000..87dce180 --- /dev/null +++ b/AST_CRON_mix_recordings_BASIC.pl @@ -0,0 +1,100 @@ +#!/usr/bin/perl +# +# AST_CRON_mix_recordings_BASIC.pl +# runs every 5 minutes and mixes the call recordings in the monitor together +# and puts the resulting ALL file into the DONE directory in the "monitor" dir +# +# soxmix is REQUIRED to use this script, soxmix is available only as part of +# the sox audio package, and only in newer versions. Make sure you have soxmix +# installed properly and in your path +# +# put an entry into the cron of of your asterisk machine to run this script +# every 5 minutes or however often you desire +# +# make sure that the following directories exist: +# /var/spool/asterisk/monitor # default Asterisk recording directory +# /var/spool/asterisk/monitor/DONE # where the combined files are put +# /var/spool/asterisk/monitor/ORIG # where the original in/out files are put +# +# This program assumes that recordings are saved as .wav +# should be easy to change this code if you use .gsm instead +# +# This program also sends the ALL combined file to an FTP server for archival +# purposes, you can comment out the Net::Ping and Net::FTP lines as well as the +# file transfer section of the code to deactivate remote copying of the +# recording files +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# +# +# 51021-1058 Added quotes around CLI executed commands +# 51122-1456 Added soxmix binary path check +# 60318-0921 Added ability to mix gsm audio files +# + + +#$v=1; + + +### directory where in/out recordings are saved to by Asterisk +$dir1 = '/var/spool/asterisk/monitor'; + +$soxmixbin = ''; +if ( -e ('/usr/bin/soxmix')) {$soxmixbin = '/usr/bin/soxmix';} +else + { + if ( -e ('/usr/local/bin/soxmix')) {$soxmixbin = '/usr/local/bin/soxmix';} + else + { + print "Can't find soxmix binary! Exiting...\n"; + exit; + } + } + + opendir(FILE, "$dir1/"); + @FILES = readdir(FILE); + +$i=0; +foreach(@FILES) + { + $size1 = 0; + $size2 = 0; + + if ( (length($FILES[$i]) > 4) && (!-d $FILES[$i]) ) + { + + $size1 = (-s "$dir1/$FILES[$i]"); + if ($v) {print "$FILES[$i] $size1\n";} + sleep(1); + $size2 = (-s "$dir1/$FILES[$i]"); + if ($v) {print "$FILES[$i] $size2\n\n";} + + + if ( ($FILES[$i] !~ /out\.wav|out\.gsm/i) && ($size1 eq $size2) && (length($FILES[$i]) > 4)) + { + $INfile = $FILES[$i]; + $OUTfile = $FILES[$i]; + $OUTfile =~ s/-in\.wav/-out.wav/gi; + $OUTfile =~ s/-in\.gsm/-out.gsm/gi; + $ALLfile = $FILES[$i]; + $ALLfile =~ s/-in\.wav/-all.wav/gi; + $ALLfile =~ s/-in\.gsm/-all.gsm/gi; + + if ($v) {print "|$INfile| |$OUTfile| |$ALLfile|\n\n";} + + `$soxmixbin "$dir1/$INfile" "$dir1/$OUTfile" "$dir1/$ALLfile"`; + if ($v) {print "|$INfile| |$OUTfile| |$ALLfile|\n\n";} + if (!$T) + { + `mv -f "$dir1/$INfile" "$dir1/ORIG/$INfile"`; + `mv -f "$dir1/$OUTfile" "$dir1/ORIG/$OUTfile"`; + `mv -f "$dir1/$ALLfile" "$dir1/DONE/$ALLfile"`; + } + } + } + $i++; + } + +if ($v) {print "DONE... EXITING\n\n";} + +exit; diff --git a/AST_CRON_mix_recordings_GSM.pl b/AST_CRON_mix_recordings_GSM.pl new file mode 100644 index 00000000..02c5ef63 --- /dev/null +++ b/AST_CRON_mix_recordings_GSM.pl @@ -0,0 +1,151 @@ +#!/usr/bin/perl +# +# AST_CRON_mix_recordings_GSM.pl +# runs every 5 minutes and mixes the call recordings in the monitor together +# and puts the resulting ALL file into the DONE directory in the "monitor" dir +# and converts the ALL file to GSM format to save space. +# +# soxmix is REQUIRED to use this script, soxmix is available only as part of +# the sox audio package, and only in newer versions. Make sure you have soxmix +# installed properly and in your path +# +# put an entry into the cron of of your asterisk machine to run this script +# every 5 minutes or however often you desire +# +# make sure that the following directories exist: +# /var/spool/asterisk/monitor # default Asterisk recording directory +# /var/spool/asterisk/monitor/DONE # where the combined files are put +# /var/spool/asterisk/monitor/ORIG # where the original in/out files are put +# +# This program assumes that recordings are saved as .wav +# should be easy to change this code if you use .gsm instead +# +# This program also sends the ALL combined file to an FTP server for archival +# purposes, you can comment out the Net::Ping and Net::FTP lines as well as the +# file transfer section of the code to deactivate remote copying of the +# recording files +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# +# +# 51021-1058 Added quotes around CLI executed commands +# 51122-1455 Added soxmix and sox binary path check +# + + +#$v=1; + +# Customize variables for FTP +$FTP_host = '10.0.0.4'; +$FTP_user = 'cron'; +$FTP_pass = 'test'; +$FTP_dir = 'RECORDINGS'; +$FTP_port = '21'; + +### directory where in/out recordings are saved to by Asterisk +$dir1 = '/var/spool/asterisk/monitor'; + +$soxmixbin = ''; +if ( -e ('/usr/bin/soxmix')) {$soxmixbin = '/usr/bin/soxmix';} +else + { + if ( -e ('/usr/local/bin/soxmix')) {$soxmixbin = '/usr/local/bin/soxmix';} + else + { + print "Can't find soxmix binary! Exiting...\n"; + exit; + } + } +$soxbin = ''; +if ( -e ('/usr/bin/sox')) {$soxbin = '/usr/bin/sox';} +else + { + if ( -e ('/usr/local/bin/sox')) {$soxbin = '/usr/local/bin/sox';} + else + { + print "Can't find sox binary! Exiting...\n"; + exit; + } + } + +use Net::Ping; +use Net::FTP; + + + opendir(FILE, "$dir1/"); + @FILES = readdir(FILE); + +$i=0; +foreach(@FILES) + { + $size1 = 0; + $size2 = 0; + + if ( (length($FILES[$i]) > 4) && (!-d $FILES[$i]) ) + { + + $size1 = (-s "$dir1/$FILES[$i]"); + if ($v) {print "$FILES[$i] $size1\n";} + sleep(1); + $size2 = (-s "$dir1/$FILES[$i]"); + if ($v) {print "$FILES[$i] $size2\n\n";} + + + if ( ($FILES[$i] !~ /out\.wav/i) && ($size1 eq $size2) && (length($FILES[$i]) > 4)) + { + $INfile = $FILES[$i]; + $OUTfile = $FILES[$i]; + $OUTfile =~ s/-in\.wav/-out.wav/gi; + $ALLfile = $FILES[$i]; + $ALLfile =~ s/-in\.wav/-all.wav/gi; + $GSMfile = $ALLfile; + $GSMfile =~ s/-all\.wav/-all.gsm/gi; + + if ($v) {print "|$INfile| |$OUTfile| |$ALLfile|\n\n";} + + `$soxmixbin "$dir1/$INfile" "$dir1/$OUTfile" "$dir1/$ALLfile"`; + if ($v) {print "|$INfile| |$OUTfile| |$ALLfile|\n\n";} + if (!$T) + { + `mv -f "$dir1/$INfile" "$dir1/ORIG/$INfile"`; + `mv -f "$dir1/$OUTfile" "$dir1/ORIG/$OUTfile"`; + `mv -f "$dir1/$ALLfile" "$dir1/DONE/$ALLfile"`; + } + else + { + `cp -f "$dir1/$ALLfile" "$dir1/DONE/$ALLfile"`; + } + + `$soxbin "$dir1/DONE/$ALLfile" "$dir1/DONE/$GSMfile"`; + + if (!$T) + { + `rm -f "$dir1/DONE/$ALLfile"`; + } + + if($DB){print STDERR "\n|/usr/bin/sox $live_folder/$filename[$k]$WAV $arch_folder/$filename[$k]$GSM|\n";} + chmod 0755, "$dir1/DONE/$GSMfile"; + + ### BEGIN Remote file transfer + # $p = Net::Ping->new(); + # $ping_good = $p->ping("$FTP_host"); + + # if ($ping_good) + # { + $ftp = Net::FTP->new("$FTP_host", Port => $FTP_port, Debug => 0, Passive => 1); + $ftp->login("$FTP_user","$FTP_pass"); + $ftp->cwd("$FTP_dir"); + $ftp->binary(); + $ftp->put("$dir1/DONE/$GSMfile", "$GSMfile"); + $ftp->quit; + # } + ### END Remote file transfer + + } + } + $i++; + } + +if ($v) {print "DONE... EXITING\n\n";} + +exit; diff --git a/AST_CRON_mix_recordings_MP3.pl b/AST_CRON_mix_recordings_MP3.pl new file mode 100644 index 00000000..2133f485 --- /dev/null +++ b/AST_CRON_mix_recordings_MP3.pl @@ -0,0 +1,152 @@ +#!/usr/bin/perl +# +# AST_CRON_mix_recordings_MP3.pl +# runs every 5 minutes and mixes the call recordings in the monitor together +# and puts the resulting ALL file into the DONE directory in the "monitor" dir +# and converts the ALL file to GSM format to save space. +# +# soxmix is REQUIRED to use this script, soxmix is available only as part of +# the sox audio package, and only in newer versions. Make sure you have soxmix +# installed properly and in your path +# +# put an entry into the cron of of your asterisk machine to run this script +# every 5 minutes or however often you desire +# +# make sure that the following directories exist: +# /var/spool/asterisk/monitor # default Asterisk recording directory +# /var/spool/asterisk/monitor/DONE # where the combined files are put +# /var/spool/asterisk/monitor/ORIG # where the original in/out files are put +# +# This program assumes that recordings are saved as .wav +# should be easy to change this code if you use .gsm instead +# +# This program also sends the ALL combined file to an FTP server for archival +# purposes, you can comment out the Net::Ping and Net::FTP lines as well as the +# file transfer section of the code to deactivate remote copying of the +# recording files +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# Contributions by Mike Lord +# +# 51021-1058 - Added quotes around CLI executed commands +# 51122-1455 - Added soxmix and sox binary path check +# 60616-1027 - Modified to convert to MP3 format +# + + +#$v=1; + +# Customize variables for FTP +$FTP_host = '10.0.0.4'; +$FTP_user = 'cron'; +$FTP_pass = 'test'; +$FTP_dir = 'recordings'; +$FTP_port = '21'; + +### directory where in/out recordings are saved to by Asterisk +$dir1 = '/var/spool/asterisk/monitor'; + +$soxmixbin = ''; +if ( -e ('/usr/bin/soxmix')) {$soxmixbin = '/usr/bin/soxmix';} +else + { + if ( -e ('/usr/local/bin/soxmix')) {$soxmixbin = '/usr/local/bin/soxmix';} + else + { + print "Can't find soxmix binary! Exiting...\n"; + exit; + } + } +$lamebin = ''; +if ( -e ('/usr/bin/lame')) {$lamebin = '/usr/bin/lame';} +else + { + if ( -e ('/usr/local/bin/lame')) {$lamebin = '/usr/local/bin/lame';} + else + { + print "Can't find lame binary! Exiting...\n"; + exit; + } + } + +use Net::Ping; +use Net::FTP; + + + opendir(FILE, "$dir1/"); + @FILES = readdir(FILE); + +$i=0; +foreach(@FILES) + { + $size1 = 0; + $size2 = 0; + + if ( (length($FILES[$i]) > 4) && (!-d $FILES[$i]) ) + { + + $size1 = (-s "$dir1/$FILES[$i]"); + if ($v) {print "$FILES[$i] $size1\n";} + sleep(1); + $size2 = (-s "$dir1/$FILES[$i]"); + if ($v) {print "$FILES[$i] $size2\n\n";} + + + if ( ($FILES[$i] !~ /out\.wav/i) && ($size1 eq $size2) && (length($FILES[$i]) > 4)) + { + $INfile = $FILES[$i]; + $OUTfile = $FILES[$i]; + $OUTfile =~ s/-in\.wav/-out.wav/gi; + $ALLfile = $FILES[$i]; + $ALLfile =~ s/-in\.wav/-all.wav/gi; + $MP3file = $ALLfile; + $MP3file =~ s/-all\.wav/-all.mp3/gi; + + if ($v) {print "|$INfile| |$OUTfile| |$ALLfile|\n\n";} + + `$soxmixbin "$dir1/$INfile" "$dir1/$OUTfile" "$dir1/$ALLfile"`; + if ($v) {print "|$INfile| |$OUTfile| |$ALLfile|\n\n";} + if (!$T) + { + `mv -f "$dir1/$INfile" "$dir1/ORIG/$INfile"`; + `mv -f "$dir1/$OUTfile" "$dir1/ORIG/$OUTfile"`; + `mv -f "$dir1/$ALLfile" "$dir1/DONE/$ALLfile"`; + } + else + { + `cp -f "$dir1/$ALLfile" "$dir1/DONE/$ALLfile"`; + } + + `$lamebin -b 16 -m m --silent "$dir1/DONE/$ALLfile" "$dir1/DONE/$MP3file"`; + + if (!$T) + { + `rm -f "$dir1/DONE/$ALLfile"`; + } + + if($DB){print STDERR "\n|/usr/bin/sox $live_folder/$filename[$k]$WAV $arch_folder/$filename[$k]$GSM|\n";} + chmod 0755, "$dir1/DONE/$MP3file"; + + ### BEGIN Remote file transfer + # $p = Net::Ping->new(); + # $ping_good = $p->ping("$FTP_host"); + + # if ($ping_good) + # { + $ftp = Net::FTP->new("$FTP_host", Port => $FTP_port, Debug => 0, Passive => 1); + $ftp->login("$FTP_user","$FTP_pass"); + $ftp->cwd("$FTP_dir"); + $ftp->binary(); + $ftp->put("$dir1/DONE/$MP3file", "$MP3file"); + $ftp->quit; + # } + ### END Remote file transfer + + } + } + $i++; + } + +if ($v) {print "DONE... EXITING\n\n";} + +exit; diff --git a/AST_DB_optimize.pl b/AST_DB_optimize.pl new file mode 100644 index 00000000..2c1aabf2 --- /dev/null +++ b/AST_DB_optimize.pl @@ -0,0 +1,153 @@ +#!/usr/bin/perl +# +# AST_DB_optimize.pl version 0.1 +# +# DESCRIPTION: +# optimizes the tables used in the asterisk MySQL database +# +# It is recommended that you run this program on the local Asterisk machine +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# + +### Make sure this file is in a libs path or put the absolute path to it +require("/home/cron/AST_SERVER_conf.pl"); # local configuration file + +if (!$DB_port) {$DB_port='3306';} + +use Net::MySQL; + + my $dbhA = Net::MySQL->new(hostname => "$DB_server", database => "$DB_database", user => "$DB_user", password => "$DB_pass", port => "$DB_port") + or die "Couldn't connect to database: $DB_server - $DB_database\n"; + + + + + $stmtA = "optimize table call_log;"; + if($DB){print STDERR "\n|$stmtA|\n";} + if (!$T) {$dbhA->query($stmtA); } + if ($dbhA->has_selected_record) + { + $iterA=$dbhA->create_record_iterator; + while ($recordA = $iterA->each) + { + if ($DB) {print "|",$recordA->[0],"|",$recordA->[1],"|",$recordA->[2],"|",$recordA->[3],"|","\n";} + } + } + + + $stmtA = "optimize table park_log;"; + if($DB){print STDERR "\n|$stmtA|\n";} + if (!$T) {$dbhA->query($stmtA); } + if ($dbhA->has_selected_record) + { + $iterA=$dbhA->create_record_iterator; + while ($recordA = $iterA->each) + { + if ($DB) {print "|",$recordA->[0],"|",$recordA->[1],"|",$recordA->[2],"|",$recordA->[3],"|","\n";} + } + } + + + $stmtA = "optimize table vicidial_log;"; + if($DB){print STDERR "\n|$stmtA|\n";} + if (!$T) {$dbhA->query($stmtA); } + if ($dbhA->has_selected_record) + { + $iterA=$dbhA->create_record_iterator; + while ($recordA = $iterA->each) + { + if ($DB) {print "|",$recordA->[0],"|",$recordA->[1],"|",$recordA->[2],"|",$recordA->[3],"|","\n";} + } + } + + + $stmtA = "optimize table vicidial_closer_log;"; + if($DB){print STDERR "\n|$stmtA|\n";} + if (!$T) {$dbhA->query($stmtA); } + if ($dbhA->has_selected_record) + { + $iterA=$dbhA->create_record_iterator; + while ($recordA = $iterA->each) + { + if ($DB) {print "|",$recordA->[0],"|",$recordA->[1],"|",$recordA->[2],"|",$recordA->[3],"|","\n";} + } + } + + + $stmtA = "optimize table vicidial_xfer_log;"; + if($DB){print STDERR "\n|$stmtA|\n";} + if (!$T) {$dbhA->query($stmtA); } + if ($dbhA->has_selected_record) + { + $iterA=$dbhA->create_record_iterator; + while ($recordA = $iterA->each) + { + if ($DB) {print "|",$recordA->[0],"|",$recordA->[1],"|",$recordA->[2],"|",$recordA->[3],"|","\n";} + } + } + + + $stmtA = "optimize table vicidial_list;"; + if($DB){print STDERR "\n|$stmtA|\n";} + if (!$T) {$dbhA->query($stmtA); } + if ($dbhA->has_selected_record) + { + $iterA=$dbhA->create_record_iterator; + while ($recordA = $iterA->each) + { + if ($DB) {print "|",$recordA->[0],"|",$recordA->[1],"|",$recordA->[2],"|",$recordA->[3],"|","\n";} + } + } + + + $stmtA = "optimize table vicidial_manager;"; + if($DB){print STDERR "\n|$stmtA|\n";} + if (!$T) {$dbhA->query($stmtA); } + if ($dbhA->has_selected_record) + { + $iterA=$dbhA->create_record_iterator; + while ($recordA = $iterA->each) + { + if ($DB) {print "|",$recordA->[0],"|",$recordA->[1],"|",$recordA->[2],"|",$recordA->[3],"|","\n";} + } + } + + + $stmtA = "optimize table vicidial_auto_calls;"; + if($DB){print STDERR "\n|$stmtA|\n";} + if (!$T) {$dbhA->query($stmtA); } + if ($dbhA->has_selected_record) + { + $iterA=$dbhA->create_record_iterator; + while ($recordA = $iterA->each) + { + if ($DB) {print "|",$recordA->[0],"|",$recordA->[1],"|",$recordA->[2],"|",$recordA->[3],"|","\n";} + } + } + + + $stmtA = "optimize table vicidial_live_agents;"; + if($DB){print STDERR "\n|$stmtA|\n";} + if (!$T) {$dbhA->query($stmtA); } + if ($dbhA->has_selected_record) + { + $iterA=$dbhA->create_record_iterator; + while ($recordA = $iterA->each) + { + if ($DB) {print "|",$recordA->[0],"|",$recordA->[1],"|",$recordA->[2],"|",$recordA->[3],"|","\n";} + } + } + + + + $dbhA->close; + + +exit; + + + + + + diff --git a/AST_SERVER_conf.pl b/AST_SERVER_conf.pl new file mode 100644 index 00000000..ba87cee3 --- /dev/null +++ b/AST_SERVER_conf.pl @@ -0,0 +1,25 @@ +#!/usr/bin/perl + +# AST_SERVER_conf.pl +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# + +# Customized Variables +$server_ip = '10.10.10.15'; # Asterisk server IP +$DB_server = 'localhost'; # MySQL server IP +$DB_database = 'asterisk'; # MySQL database name +$DB_user = 'cron'; # MySQL user +$DB_pass = '1234'; # MySQL pass +$DB_port = '3306'; # MySQL connection port + +$LOGfile = '/home/cron/LOG_AST_update.log'; +$telnetlog = '/home/cron/telnetlog.log'; +$MSLOGfile = '/home/cron/MSLOG_AST_update.log'; +$MStelnetlog = '/home/cron/MStelnetlog.log'; +$LILOGfile = '/home/cron/LILOG_AST_update.log'; +$LItelnetlog = '/home/cron/LItelnetlog.log'; +$KHLOGfile = '/home/cron/KHLOG_AST_update.log'; +$VDADLOGfile = '/home/cron/VDLOG_AST_update.log'; + +return 1; diff --git a/AST_VDauto_dial.pl b/AST_VDauto_dial.pl new file mode 100644 index 00000000..aeec29e0 --- /dev/null +++ b/AST_VDauto_dial.pl @@ -0,0 +1,887 @@ +#!/usr/bin/perl +# +# AST_VDauto_dial.pl version 0.11 +# +# DESCRIPTION: +# uses Net::MySQL to place auto_dial calls on the VICIDIAL dialer system +# +# SUMMARY: +# This program was designed for people using the Asterisk PBX with VICIDIAL +# +# For the client to use VICIDIAL, this program must be in the cron constantly +# +# For this program to work you need to have the "asterisk" MySQL database +# created and create the tables listed in the CONF_MySQL.txt file, also make sure +# that the machine running this program has read/write/update/delete access +# to that database +# +# It is recommended that you run this program on the local Asterisk machine +# +# This script is to run perpetually querying every second to place new phone +# calls from the vicidial_hopper based upon how many available agents there are +# and the value of the auto_dial_level setting in the campaign screen of the +# admin web page +# +# It is good practice to keep this program running by placing the associated +# KEEPALIVE script running every minute to ensure this program is always running +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# +# changes: +# 50125-1201 - Changed dial timeout to 120 seconds from 180 seconds +# 50317-0954 - Added duplicate check per cycle to account for DB lockups +# 50322-1302 - Added campaign custom callerid feature +# 50324-1353 - Added optional variable to record ring time thru separate diap prefix +# 50606-2308 - Added code to ensure no calls placed out on inactive campaign +# 50617-1248 - Added code to place LOGOUT entry in auto-paused user logs +# 50620-1349 - Added custom vdad transfer AGI extension per campaign +# 50810-1610 - Added database server variable definitions lookup +# 50810-1630 - Added max_vicidial_trunks server limiter on active lines +# 50812-0957 - corrected max_trunks logic, added update of server every 25 sec +# 60120-1522 - corrected time error for hour variable, caused agi problems +# 60427-1223 - Fixed Blended in/out CLOSER campaign issue +# 60608-1134 - Altered vac table field of call_type for IN OUT distinction +# 60612-1324 - Altered dead call section to accept BUSY detection from VD_hangup +# - Altered dead call section to accept DISCONNECT detection from VD_hangup +# 60614-1142 - Added code to work with recycled leads, multi called_since_last_reset values +# - Removed gmt lead validation because it is already done by VDhopper +# + + +### begin parsing run-time options ### +if (length($ARGV[0])>1) +{ + $i=0; + while ($#ARGV >= $i) + { + $args = "$args $ARGV[$i]"; + $i++; + } + + if ($args =~ /--help/i) + { + print "allowed run time options:\n [-t] = test\n [-debug] = verbose debug messages\n [--delay=XXX] = delay of XXX seconds per loop, default 2.5 seconds\n\n"; + } + else + { + if ($args =~ /--delay=/i) + { + @data_in = split(/--delay=/,$args); + $loop_delay = $data_in[1]; + print " LOOP DELAY OVERRIDE!!!!! = $loop_delay seconds\n\n"; + $loop_delay = ($loop_delay * 1000); + } + else + { + $loop_delay = '2500'; + } + if ($args =~ /-debug/i) + { + $DB=1; # Debug flag, set to 0 for no debug messages, On an active system this will generate hundreds of lines of output per minute + } + if ($args =~ /-t/i) + { + $TEST=1; + $T=1; + } + } +} +else +{ +print "no command line options set\n"; + $loop_delay = '2500'; + $DB=1; +} +### end parsing run-time options ### + + +# constants +$US='__'; +$MT[0]=''; +$RECcount=''; ### leave blank for no REC count +$RECprefix='7'; ### leave blank for no REC prefix + +### Make sure this file is in a libs path or put the absolute path to it +require("/home/cron/AST_SERVER_conf.pl"); # local configuration file + +if (!$DB_port) {$DB_port='3306';} + + &get_time_now; # update time/date variables + + $event_string='PROGRAM STARTED||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||'; + &event_logger; # writes to the log and if debug flag is set prints to STDOUT + +use lib './lib', '../lib'; +use Time::HiRes ('gettimeofday','usleep','sleep'); # necessary to have perl sleep command of less than one second +use Net::MySQL; + + ### connect to MySQL database defined in the AST_SERVER_conf.pl file + my $dbhA = Net::MySQL->new(hostname => "$DB_server", database => "$DB_database", user => "$DB_user", password => "$DB_pass", port => "$DB_port") + or die "Couldn't connect to database: $DB_server - $DB_database\n"; + +### Grab Server values from the database +$stmtA = "SELECT telnet_host,telnet_port,ASTmgrUSERNAME,ASTmgrSECRET,ASTmgrUSERNAMEupdate,ASTmgrUSERNAMElisten,ASTmgrUSERNAMEsend,max_vicidial_trunks,answer_transfer_agent,local_gmt,ext_context FROM servers where server_ip = '$server_ip';"; +$dbhA->query("$stmtA"); +if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $DBtelnet_host = "$record->[0]"; + $DBtelnet_port = "$record->[1]"; + $DBASTmgrUSERNAME = "$record->[2]"; + $DBASTmgrSECRET = "$record->[3]"; + $DBASTmgrUSERNAMEupdate = "$record->[4]"; + $DBASTmgrUSERNAMElisten = "$record->[5]"; + $DBASTmgrUSERNAMEsend = "$record->[6]"; + $DBmax_vicidial_trunks = "$record->[7]"; + $DBanswer_transfer_agent= "$record->[8]"; + $DBSERVER_GMT = "$record->[9]"; + $DBext_context = "$record->[10]"; + if ($DBtelnet_host) {$telnet_host = $DBtelnet_host;} + if ($DBtelnet_port) {$telnet_port = $DBtelnet_port;} + if ($DBASTmgrUSERNAME) {$ASTmgrUSERNAME = $DBASTmgrUSERNAME;} + if ($DBASTmgrSECRET) {$ASTmgrSECRET = $DBASTmgrSECRET;} + if ($DBASTmgrUSERNAMEupdate) {$ASTmgrUSERNAMEupdate = $DBASTmgrUSERNAMEupdate;} + if ($DBASTmgrUSERNAMElisten) {$ASTmgrUSERNAMElisten = $DBASTmgrUSERNAMElisten;} + if ($DBASTmgrUSERNAMEsend) {$ASTmgrUSERNAMEsend = $DBASTmgrUSERNAMEsend;} + if ($DBmax_vicidial_trunks) {$max_vicidial_trunks = $DBmax_vicidial_trunks;} + if ($DBanswer_transfer_agent) {$answer_transfer_agent = $DBanswer_transfer_agent;} + if ($DBSERVER_GMT) {$SERVER_GMT = $DBSERVER_GMT;} + if ($DBext_context) {$ext_context = $DBext_context;} + } + } + + + $event_string='LOGGED INTO MYSQL SERVER ON 1 CONNECTION|'; + &event_logger; + +$one_day_interval = 12; # 1 month loops for one year +while($one_day_interval > 0) +{ + + $endless_loop=5760000; # 30 days minutes at XXX seconds per loop + + while($endless_loop > 0) + { + &get_time_now; + + ############################################################################### + ###### first figure out how many calls should be placed for each campaign per server + ############################################################################### + @DBlive_user=@MT; + @DBlive_server_ip=@MT; + @DBlive_campaign=@MT; + @DBlive_conf_exten=@MT; + @DBcampaigns=@MT; + @DBIPaddress=@MT; + @DBIPcampaign=@MT; + @DBIPactive=@MT; + @DBIPvdadexten=@MT; + @DBIPcount=@MT; + @DBIPadlevel=@MT; + @DBIPdialtimeout=@MT; + @DBIPdialprefix=@MT; + @DBIPcampaigncid=@MT; + @DBIPexistcalls=@MT; + @DBIPgoalcalls=@MT; + @DBIPmakecalls=@MT; + @DBIPclosercamp=@MT; + + $active_line_counter=0; + $user_counter=0; + $user_campaigns = '|'; + $user_campaigns_counter = 0; + $user_campaignIP = '|'; + $user_CIPct = 0; + + ##### Get a listing of the users that are active and ready to take calls + ##### Also get a listing of the campaigns and campaigns/serverIP that will be used + $dbhA->query("SELECT user,server_ip,campaign_id,conf_exten FROM vicidial_live_agents where status IN('READY','QUEUE','INCALL','DONE') and server_ip='$server_ip' and last_update_time > '$BDtsSQLdate' order by last_call_time"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $DBlive_user[$user_counter] = "$record->[0]"; + $DBlive_server_ip[$user_counter] = "$record->[1]"; + $DBlive_campaign[$user_counter] = "$record->[2]"; + $DBlive_conf_exten[$user_counter] = "$record->[3]"; + + if ($user_campaigns !~ /\|$DBlive_campaign[$user_counter]\|/i) + { + $user_campaigns .= "$DBlive_campaign[$user_counter]|"; + $DBcampaigns[$user_campaigns_counter] = $DBlive_campaign[$user_counter]; + $user_campaigns_counter++; + } + if ($user_campaignIP !~ /\|$DBlive_campaign[$user_counter]__$DBlive_server_ip[$user_counter]\|/i) + { + $user_campaignIP .= "$DBlive_campaign[$user_counter]__$DBlive_server_ip[$user_counter]|"; + $DBIPcampaign[$user_CIPct] = "$DBlive_campaign[$user_counter]"; + $DBIPaddress[$user_CIPct] = "$DBlive_server_ip[$user_counter]"; + $user_CIPct++; + } + $user_counter++; + } + } + + $event_string="LIVE AGENTS LOGGED IN: $user_counter"; + &event_logger; + + $user_CIPct = 0; + foreach(@DBIPcampaign) + { + $user_counter=0; + foreach(@DBlive_campaign) + { + if ( ($DBlive_campaign[$user_counter] =~ /$DBIPcampaign[$user_CIPct]/i) && ($DBlive_server_ip[$user_counter] =~ /$DBIPaddress[$user_CIPct]/i) ) + { + $DBIPcount[$user_CIPct]++ + } + $user_counter++; + } + + ### grab the dial_level and multiply by active agents to get your goalcalls + $DBIPadlevel[$user_CIPct]=0; + $dbhA->query("SELECT auto_dial_level,local_call_time,dial_timeout,dial_prefix,campaign_cid,active,campaign_vdad_exten,closer_campaigns FROM vicidial_campaigns where campaign_id='$DBIPcampaign[$user_CIPct]'"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $DBIPadlevel[$user_CIPct] = "$record->[0]"; + $DBIPcalltime[$user_CIPct] = "$record->[1]"; + $DBIPdialtimeout[$user_CIPct] = "$record->[2]"; + $DBIPdialprefix[$user_CIPct] = "$record->[3]"; + $DBIPcampaigncid[$user_CIPct] = "$record->[4]"; + $DBIPactive[$user_CIPct] = "$record->[5]"; + $DBIPvdadexten[$user_CIPct] = "$record->[6]"; + $DBIPclosercamp[$user_CIPct] = "$record->[7]"; + } + } + + $DBIPgoalcalls[$user_CIPct] = ($DBIPadlevel[$user_CIPct] * $DBIPcount[$user_CIPct]); + if ($DBIPactive[$user_CIPct] =~ /N/) {$DBIPgoalcalls[$user_CIPct] = 0;} + $DBIPgoalcalls[$user_CIPct] = sprintf("%.0f", $DBIPgoalcalls[$user_CIPct]); + + $event_string="$DBIPcampaign[$user_CIPct] $DBIPaddress[$user_CIPct]: agents: $DBIPcount[$user_CIPct] dial_level: $DBIPadlevel[$user_CIPct]"; + &event_logger; + + $active_line_counter=0; + $active_line_goal=0; + ### see how many total VDAD calls are going on right now for max limiter + $dbhA->query("SELECT count(*) FROM vicidial_auto_calls where server_ip='$DBIPaddress[$user_CIPct]' and status IN('SENT','RINGING','LIVE','XFER');"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $active_line_counter = "$record->[0]"; + } + } + + ### see how many calls are alrady active per campaign per server and + ### subtract that number from goalcalls to determine how many new + ### calls need to be placed in this loop + if ($DBIPcampaign[$user_CIPct] =~ /CLOSER/) + { + if (length($DBIPclosercamp[$user_CIPct]) > 2) + { + $DBIPclosercamp[$user_CIPct] =~ s/^ | -$//gi; + $DBIPclosercamp[$user_CIPct] =~ s/ /','/gi; + $DBIPclosercamp[$user_CIPct] = "'$DBIPclosercamp[$user_CIPct]'"; + } + else {$DBIPclosercamp[$user_CIPct]=''} + + $campaign_query = "( (call_type='IN' and campaign_id IN($DBIPclosercamp[$user_CIPct])) or (campaign_id='$DBIPcampaign[$user_CIPct]' and call_type='OUT') )"; + } + else {$campaign_query = "(campaign_id='$DBIPcampaign[$user_CIPct]' and call_type='OUT')";} + $dbhA->query("SELECT count(*) FROM vicidial_auto_calls where $campaign_query and server_ip='$DBIPaddress[$user_CIPct]' and status IN('SENT','RINGING','LIVE','XFER','CLOSER');"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $DBIPexistcalls[$user_CIPct] = "$record->[0]"; + } + } + + $DBIPmakecalls[$user_CIPct] = ($DBIPgoalcalls[$user_CIPct] - $DBIPexistcalls[$user_CIPct]); + $MVT_msg = ''; + $active_line_goal = ($active_line_counter + $DBIPmakecalls[$user_CIPct]); + if ($active_line_goal > $max_vicidial_trunks) + { + $MVT_msg = "MVT override: $max_vicidial_trunks"; + $DBIPmakecalls[$user_CIPct] = ($max_vicidial_trunks - $active_line_counter); + } + $event_string="$DBIPcampaign[$user_CIPct] $DBIPaddress[$user_CIPct]: Calls to place: $DBIPmakecalls[$user_CIPct] ($DBIPgoalcalls[$user_CIPct] - $DBIPexistcalls[$user_CIPct]) $MVT_msg"; + &event_logger; + + $user_CIPct++; + } + + ############################################################################### + ###### second lookup leads and place calls for each campaign/server_ip + ###### go one lead at a time and place the call by inserting a record into vicidial_manager + ############################################################################### + + $user_CIPct = 0; + foreach(@DBIPcampaign) + { + $event_string="$DBIPcampaign[$user_CIPct] $DBIPaddress[$user_CIPct]: CALLING"; + &event_logger; + $call_CMPIPct=0; + $lead_id_call_list='|'; + my $UDaffected_rows=0; + if ($call_CMPIPct < $DBIPmakecalls[$user_CIPct]) + { + $stmtA = "UPDATE vicidial_hopper set status='QUEUE', user='VDAD_$server_ip' where campaign_id='$DBIPcampaign[$user_CIPct]' and status='READY' order by hopper_id LIMIT $DBIPmakecalls[$user_CIPct]"; + print "|$stmtA|\n"; + $dbhA->query("$stmtA"); + my $UDaffected_rows = $dbhA->get_affected_rows_length; + print "hopper rows updated to QUEUE: |$UDaffected_rows|\n"; + + if ($UDaffected_rows) + { + $lead_id=''; $phone_code=''; $phone_number=''; $called_count=''; + while ($call_CMPIPct < $UDaffected_rows) + { + $stmtA = "SELECT lead_id FROM vicidial_hopper where campaign_id='$DBIPcampaign[$user_CIPct]' and status='QUEUE' and user='VDAD_$server_ip' LIMIT 1"; + print "|$stmtA|\n"; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_countCUSTDATA=0; + while ( $record = $iter->each) + { + $lead_id = "$record->[0]"; + } + } + + if ($lead_id_call_list =~ /\|$lead_id\|/) + { + print "!!!!!!!!!!!!!!!!duplicate lead_id for this run: |$lead_id| $lead_id_call_list\n"; + open(DUPout, ">>/home/cron/VDAD_DUPLICATE.$file_date") + || die "Can't open /home/cron/VDAD_DUPLICATE.$file_date: $!\n"; + print DUPout "$now_date-----$lead_id_call_list-----$lead_id\n"; + close(DUPout); + } + else + { + $stmtA = "UPDATE vicidial_hopper set status='INCALL' where lead_id='$lead_id'"; + print "|$stmtA|\n"; + $dbhA->query("$stmtA"); + my $UQaffected_rows = $dbhA->get_affected_rows_length; + print "hopper row updated to INCALL: |$UQaffected_rows|$lead_id|\n"; + + $stmtA = "SELECT * FROM vicidial_list where lead_id='$lead_id';"; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_countCUSTDATA=0; + while ( $record = $iter->each) + { + $gmt_offset_now = "$record->[8]"; + $called_since_last_reset = "$record->[9]"; + $phone_code = "$record->[10]"; + $phone_number = "$record->[11]"; + $called_count = "$record->[30]"; + + $rec_countCUSTDATA++; + } + } + + if ($rec_countCUSTDATA) + { + ### update called_count + $called_count++; + if ($called_since_last_reset =~ /^Y/) + { + if ($called_since_last_reset =~ /^Y$/) {$CSLR = 'Y1';} + else + { + $called_since_last_reset =~ s/^Y//gi; + $called_since_last_reset++; + $CSLR = "Y$called_since_last_reset"; + } + } + else {$CSLR = 'Y';} + + $stmtA = "UPDATE vicidial_list set called_since_last_reset='$CSLR', called_count='$called_count',user='VDAD' where lead_id='$lead_id'"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + + $stmtA = "DELETE FROM vicidial_hopper where lead_id='$lead_id'"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + + $CCID_on=0; $CCID=''; + $local_DEF = 'Local/'; + $local_AMP = '@'; + $Local_out_prefix = '9'; + $Local_dial_timeout = '60'; + if ($DBIPdialtimeout[$user_CIPct] > 4) {$Local_dial_timeout = $DBIPdialtimeout[$user_CIPct];} + $Local_dial_timeout = ($Local_dial_timeout * 1000); + if (length($DBIPdialprefix[$user_CIPct]) > 0) {$Local_out_prefix = "$DBIPdialprefix[$user_CIPct]";} + if (length($DBIPvdadexten[$user_CIPct]) > 0) {$VDAD_dial_exten = "$DBIPvdadexten[$user_CIPct]";} + else {$VDAD_dial_exten = "$answer_transfer_agent";} + + if (length($DBIPcampaigncid[$user_CIPct]) > 6) {$CCID = "$DBIPcampaigncid[$user_CIPct]"; $CCID_on++;} + if ($DBIPdialprefix[$user_CIPct] =~ /x/i) {$Local_out_prefix = '';} + + if ($RECcount) + { + if ( (length($RECprefix)>0) && ($called_count < $RECcount) ) + {$Local_out_prefix .= "$RECprefix";} + } + $PADlead_id = sprintf("%09s", $lead_id); while (length($PADlead_id) > 9) {chop($PADlead_id);} + + $lead_id_call_list .= "$lead_id|"; + + ### use manager middleware-app to connect the next call to the meetme room + # VmmddhhmmssLLLLLLLLL + $VqueryCID = "V$CIDdate$PADlead_id"; + if ($CCID_on) {$CIDstring = "\"$VqueryCID\" <$CCID>";} + else {$CIDstring = "$VqueryCID";} + + ### insert a NEW record to the vicidial_manager table to be processed + $stmtA = "INSERT INTO vicidial_manager values('','','$SQLdate','NEW','N','$DBIPaddress[$user_CIPct]','','Originate','$VqueryCID','Exten: $VDAD_dial_exten','Context: $ext_context','Channel: $local_DEF$Local_out_prefix$phone_code$phone_number$local_AMP$ext_context','Priority: 1','Callerid: $CIDstring','Timeout: $Local_dial_timeout','','','','')"; + $dbhA->query($stmtA); + + $event_string = "| number call dialed|$DBIPcampaign[$user_CIPct]|$VqueryCID|$stmtA|$gmt_offset_now|"; + &event_logger; + + ### insert a SENT record to the vicidial_auto_calls table + $stmtA = "INSERT INTO vicidial_auto_calls (server_ip,campaign_id,status,lead_id,callerid,phone_code,phone_number,call_time,call_type) values('$DBIPaddress[$user_CIPct]','$DBIPcampaign[$user_CIPct]','SENT','$lead_id','$VqueryCID','$phone_code','$phone_number','$SQLdate','OUT')"; + $dbhA->query($stmtA); + + ### sleep for a tenth of a second to not flood the server with new calls + usleep(1*100*1000); + + } + } + $call_CMPIPct++; + } + } + + } + + $user_CIPct++; + } + + + + + + + + &get_time_now; + + ############################################################################### + ###### third we will grab the callerids of the vicidial_auto_calls records and check for dead calls + ###### we also check to make sure that it isn't a call that has been transferred, + ###### if it has been we need to leave the vicidial_list status alone + ############################################################################### + + @KLcallerid = @MT; + @KLserver_ip = @MT; + @KLchannel = @MT; + $kill_vac=0; + + $stmtA = "SELECT callerid,server_ip,channel,uniqueid FROM vicidial_auto_calls where server_ip='$server_ip' order by call_time;"; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_countCUSTDATA=0; + while ( $record = $iter->each) + { + $KLcallerid[$kill_vac] = "$record->[0]"; + $KLserver_ip[$kill_vac] = "$record->[1]"; + $KLchannel[$kill_vac] = "$record->[2]"; + $KLuniqueid[$kill_vac] = "$record->[3]"; + + $kill_vac++; + } + } + + $kill_vac=0; + foreach(@KLcallerid) + { + if (length($KLserver_ip[$kill_vac]) > 7) + { + $end_epoch=0; $CLuniqueid=''; + + $stmtA = "SELECT end_epoch,uniqueid FROM call_log where caller_code='$KLcallerid[$kill_vac]' and server_ip='$KLserver_ip[$kill_vac]' order by end_epoch, start_time desc limit 1;"; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_countCUSTDATA=0; + while ( $record = $iter->each) + { + $end_epoch = "$record->[0]"; + $CLuniqueid = "$record->[1]"; + } + } + + if ( (length($KLuniqueid[$kill_vac]) > 15) && (length($CLuniqueid) < 15) ) + { + $stmtA = "SELECT end_epoch,uniqueid FROM call_log where uniqueid='$KLuniqueid[$kill_vac]' and server_ip='$KLserver_ip[$kill_vac]' order by end_epoch, start_time desc limit 1;"; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_countCUSTDATA=0; + while ( $record = $iter->each) + { + $end_epoch = "$record->[0]"; + $CLuniqueid = "$record->[1]"; + } + } + } + if ($end_epoch > 1000) + { + $CLlead_id=''; $auto_call_id=''; $CLstatus=''; $CLcampaign_id=''; $CLphone_number=''; $CLphone_code=''; + + $stmtA = "SELECT auto_call_id,lead_id,phone_number,status,campaign_id,phone_code FROM vicidial_auto_calls where callerid='$KLcallerid[$kill_vac]'"; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_countCUSTDATA=0; + while ( $record = $iter->each) + { + $auto_call_id = "$record->[0]"; + $CLlead_id = "$record->[1]"; + $CLphone_number = "$record->[2]"; + $CLstatus = "$record->[3]"; + $CLcampaign_id = "$record->[4]"; + $CLphone_code = "$record->[5]"; + } + } + $stmtA = "DELETE from vicidial_auto_calls where auto_call_id='$auto_call_id'"; + # $stmtA = "UPDATE vicidial_auto_calls set status='PAUSED' where callerid='$KLcallerid[$kill_vac]'"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + + $event_string = "| dead call vac deleted|$auto_call_id|$CLlead_id|$KLcallerid[$kill_vac]|$end_epoch|$affected_rows|$KLchannel[$kill_vac]|"; + &event_logger; + + if ($CLstatus !~ /XFER|CLOSER/) + { + if ($CLstatus =~ /BUSY/) {$CLnew_status = 'B';} + else + { + if ($CLstatus =~ /DISCONNECT/) {$CLnew_status = 'DC';} + else {$CLnew_status = 'NA';} + } + if ($CLstatus =~ /LIVE/) {$CLnew_status = 'DROP';} + else + { + $end_epoch = ($now_date_epoch + 1); + $stmtA = "INSERT INTO vicidial_log (uniqueid,lead_id,campaign_id,call_date,start_epoch,status,phone_code,phone_number,user,processed,length_in_sec,end_epoch) values('$CLuniqueid','$CLlead_id','$CLcampaign_id','$SQLdate','$now_date_epoch','$CLnew_status','$CLphone_code','$CLphone_number','VDAD','N','1','$end_epoch')"; + if($M){print STDERR "\n|$stmtA|\n";} + $dbhA->query($stmtA); + + $event_string = "| dead NA call added to log $CLuniqueid|$CLlead_id|$CLphone_number|$CLstatus|$CLnew_status|"; + &event_logger; + + } + + $stmtA = "UPDATE vicidial_list set status='$CLnew_status' where lead_id='$CLlead_id'"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + + $event_string = "| dead call vac lead marked $CLnew_status|$CLlead_id|$CLphone_number|$CLstatus|"; + &event_logger; + + $stmtA = "UPDATE vicidial_live_agents set status='PAUSED',random_id='10' where callerid='$KLcallerid[$kill_vac]';"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + + $event_string = "| dead call vla agent PAUSED $affected_rows|$CLlead_id|$CLphone_number|$CLstatus|"; + &event_logger; + } + else + { + $event_string = "| dead call vac XFERd do nothing|$CLlead_id|$CLphone_number|$CLstatus|"; + &event_logger; + } + } + } + $kill_vac++; + } + + + + ### pause agents that have disconnected or closed their apps over 30 seconds ago + $stmtA = "UPDATE vicidial_live_agents set status='PAUSED',random_id='10' where server_ip='$server_ip' and last_update_time < '$PDtsSQLdate' and status NOT IN('PAUSED')"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + + $event_string = "| lagged call vla agent PAUSED $affected_rows|$PDtsSQLdate|$BDtsSQLdate|$tsSQLdate|"; + &event_logger; + + if ($affected_rows > 0) + { + @VALOuser=@MT; @VALOcampaign=@MT; @VALOtimelog=@MT; @VALOextension=@MT; + $logcount=0; + $stmtA = "SELECT user,campaign_id,last_update_time,extension FROM vicidial_live_agents where server_ip='$server_ip' and status = 'PAUSED' and random_id='10' order by last_update_time desc limit $affected_rows"; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_countCUSTDATA=0; + while ( $record = $iter->each) + { + $VALOuser[$logcount] = "$record->[0]"; + $VALOcampaign[$logcount] = "$record->[1]"; + $VALOtimelog[$logcount] = "$record->[2]"; + $VALOextension[$logcount] = "$record->[3]"; + $logcount++; + } + } + $logrun=0; + foreach(@VALOuser) + { + $stmtA = "INSERT INTO vicidial_user_log (user,event,campaign_id,event_date,event_epoch) values('$VALOuser[$logrun]','LOGOUT','$VALOcampaign[$logrun]','$SQLdate','$now_date_epoch');"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + + $event_string = "| lagged agent LOGOUT entry inserted $VALOuser[$logrun]|$VALOcampaign[$logrun]|$VALOextension[$logcount]|"; + &event_logger; + + $logrun++; + } + + } + + + ### delete call records that are SENT for over 3 minutes + $stmtA = "DELETE FROM vicidial_auto_calls where server_ip='$server_ip' and call_time < '$XDSQLdate' and status NOT IN('XFER','CLOSER','LIVE')"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + + $event_string = "| lagged call vac agent DELETED $affected_rows|$XDSQLdate|"; + &event_logger; + + + + + + ############################################################################### + ###### last, wait for a little bit and repeat the loop + ############################################################################### + + ### sleep for 2 and a half seconds before beginning the loop again + usleep(1*$loop_delay*1000); + + $endless_loop--; + if($DB){print STDERR "\nloop counter: |$endless_loop|\n";} + + ### putting a blank file called "VDAD.kill" in the directory will automatically safely kill this program + if (-e '/home/cron/VDAD.kill') + { + unlink('/home/cron/VDAD.kill'); + $endless_loop=0; + $one_day_interval=0; + print "\nPROCESS KILLED MANUALLY... EXITING\n\n" + } + if ($endless_loop =~ /0$/) # run every ten cycles (about 25 seconds) + { + ### delete call records that are LIVE for over 10 minutes + $stmtA = "DELETE FROM vicidial_auto_calls where server_ip='$server_ip' and call_time < '$TDSQLdate' and status NOT IN('XFER','CLOSER')"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + + $event_string = "| lagged call vac agent DELETED $affected_rows|$TDSQLdate|LIVE|"; + &event_logger; + + ### Grab Server values from the database in case they've changed + $stmtA = "SELECT max_vicidial_trunks,answer_transfer_agent,local_gmt,ext_context FROM servers where server_ip = '$server_ip';"; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $DBmax_vicidial_trunks = "$record->[0]"; + $DBanswer_transfer_agent= "$record->[1]"; + $DBSERVER_GMT = "$record->[2]"; + $DBext_context = "$record->[3]"; + if ($DBmax_vicidial_trunks) {$max_vicidial_trunks = $DBmax_vicidial_trunks;} + if ($DBanswer_transfer_agent) {$answer_transfer_agent = $DBanswer_transfer_agent;} + if ($DBSERVER_GMT) {$SERVER_GMT = $DBSERVER_GMT;} + if ($DBext_context) {$ext_context = $DBext_context;} + } + } + + $event_string = "| updating server parameters $max_vicidial_trunks|$answer_transfer_agent|$SERVER_GMT|$ext_context|"; + &event_logger; + + &get_time_now; + + #@psoutput = `/bin/ps -f --no-headers -A`; + @psoutput = `/bin/ps -o "%p %a" --no-headers -A`; + + $running_listen = 0; + + $i=0; + foreach (@psoutput) + { + chomp($psoutput[$i]); + + @psline = split(/\/usr\/bin\/perl /,$psoutput[$i]); + + if ($psline[1] =~ /AST_manager_li/) {$running_listen++;} + + $i++; + } + + if (!$running_listen) + { + $endless_loop=0; + $one_day_interval=0; + print "\nPROCESS KILLED NO LISTENER RUNNING... EXITING\n\n"; + } + + if($DB){print "checking to see if listener is dead |$running_listen|\n";} + } + + $bad_grabber_counter=0; + + + } + + + if($DB){print "DONE... Exiting... Goodbye... See you later... Not really, initiating next loop...\n";} + + $event_string='HANGING UP|'; + &event_logger; + + $one_day_interval--; + +} + + $event_string='CLOSING DB CONNECTION|'; + &event_logger; + + + $dbhA->close; + + + if($DB){print "DONE... Exiting... Goodbye... See you later... Really I mean it this time\n";} + + +exit; + + + + + + + + + + + + + +sub get_time_now #get the current date and time and epoch for logging call lengths and datetimes +{ +$secX = time(); + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($secX); + $LOCAL_GMT_OFF = $SERVER_GMT; + $LOCAL_GMT_OFF_STD = $SERVER_GMT; + if ($isdst) {$LOCAL_GMT_OFF++;} + +$GMT_now = ($secX - ($LOCAL_GMT_OFF * 3600)); + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($GMT_now); + if ($hour < 10) {$hour = "0$hour";} + if ($min < 10) {$min = "0$min";} + + if ($DB) {print "TIME DEBUG: $LOCAL_GMT_OFF_STD|$LOCAL_GMT_OFF|$isdst| GMT: $hour:$min\n";} + +($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); +$year = ($year + 1900); +$mon++; +if ($mon < 10) {$mon = "0$mon";} +if ($mday < 10) {$mday = "0$mday";} +if ($hour < 10) {$hour = "0$hour";} +if ($min < 10) {$min = "0$min";} +if ($sec < 10) {$sec = "0$sec";} + +$now_date_epoch = time(); +$now_date = "$year-$mon-$mday $hour:$min:$sec"; +$file_date = "$year-$mon-$mday"; + $CIDdate = "$mon$mday$hour$min$sec"; + $tsSQLdate = "$year$mon$mday$hour$min$sec"; + $SQLdate = "$year-$mon-$mday $hour:$min:$sec"; + +$BDtarget = ($secX - 10); +($Bsec,$Bmin,$Bhour,$Bmday,$Bmon,$Byear,$Bwday,$Byday,$Bisdst) = localtime($BDtarget); +$Byear = ($Byear + 1900); +$Bmon++; +if ($Bmon < 10) {$Bmon = "0$Bmon";} +if ($Bmday < 10) {$Bmday = "0$Bmday";} +if ($Bhour < 10) {$Bhour = "0$Bhour";} +if ($Bmin < 10) {$Bmin = "0$Bmin";} +if ($Bsec < 10) {$Bsec = "0$Bsec";} + $BDtsSQLdate = "$Byear$Bmon$Bmday$Bhour$Bmin$Bsec"; + +$PDtarget = ($secX - 30); +($Psec,$Pmin,$Phour,$Pmday,$Pmon,$Pyear,$Pwday,$Pyday,$Pisdst) = localtime($PDtarget); +$Pyear = ($Pyear + 1900); +$Pmon++; +if ($Pmon < 10) {$Pmon = "0$Pmon";} +if ($Pmday < 10) {$Pmday = "0$Pmday";} +if ($Phour < 10) {$Phour = "0$Phour";} +if ($Pmin < 10) {$Pmin = "0$Pmin";} +if ($Psec < 10) {$Psec = "0$Psec";} + $PDtsSQLdate = "$Pyear$Pmon$Pmday$Phour$Pmin$Psec"; + +$XDtarget = ($secX - 120); +($Xsec,$Xmin,$Xhour,$Xmday,$Xmon,$Xyear,$Xwday,$Xyday,$Xisdst) = localtime($XDtarget); +$Xyear = ($Xyear + 1900); +$Xmon++; +if ($Xmon < 10) {$Xmon = "0$Xmon";} +if ($Xmday < 10) {$Xmday = "0$Xmday";} +if ($Xhour < 10) {$Xhour = "0$Xhour";} +if ($Xmin < 10) {$Xmin = "0$Xmin";} +if ($Xsec < 10) {$Xsec = "0$Xsec";} + $XDSQLdate = "$Xyear-$Xmon-$Xmday $Xhour:$Xmin:$Xsec"; + +$TDtarget = ($secX - 600); +($Tsec,$Tmin,$Thour,$Tmday,$Tmon,$Tyear,$Twday,$Tyday,$Tisdst) = localtime($TDtarget); +$Tyear = ($Tyear + 1900); +$Tmon++; +if ($Tmon < 10) {$Tmon = "0$Tmon";} +if ($Tmday < 10) {$Tmday = "0$Tmday";} +if ($Thour < 10) {$Thour = "0$Thour";} +if ($Tmin < 10) {$Tmin = "0$Tmin";} +if ($Tsec < 10) {$Tsec = "0$Tsec";} + $TDSQLdate = "$Tyear-$Tmon-$Tmday $Thour:$Tmin:$Tsec"; + +} + + + + + +sub event_logger +{ + +if ($DB) {print "$now_date|$event_string|\n";} + ### open the log file for writing ### + open(Lout, ">>$VDADLOGfile") + || die "Can't open $VDADLOGfile: $!\n"; + + print Lout "$now_date|$event_string|\n"; + + close(Lout); + +$event_string=''; +} diff --git a/AST_VDhopper.pl b/AST_VDhopper.pl new file mode 100644 index 00000000..ab55395c --- /dev/null +++ b/AST_VDhopper.pl @@ -0,0 +1,1192 @@ +#!/usr/bin/perl +# +# AST_VDhopper.pl version 0.9 +# +# DESCRIPTION: +# uses Net::MySQL to update the VICIDIAL leads hopper for the new streamlined +# approach of allocating leads to client machines. +# +# SUMMARY: +# This program was designed for people using the Asterisk PBX with VICIDIAL +# +# For the client to use VICIDIAL, this program must be in the cron running +# every minute +# +# For this program to work you need to have the "asterisk" MySQL database +# created and create the tables listed in the CONF_MySQL.txt file, also make sure +# that the machine running this program has read/write/update/delete access +# to that database +# +# It is recommended that you run this program on the local Asterisk machine +# +# If this script is run ever minute and you are getting close to no leads after +# a minute, you may want to play with the variables below to streamline for +# your usage +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# +# 50810-1613 - Added database server variable definitions lookup +# 60215-1106 - Added Scheduled Callback release functionality +# 60228-1623 - Change Callback activation to set the called_since_last_reset=N +# 60228-1735 - Added hopper gmt validation to remove gmt outside of time range +# 60320-0932 - Added inactive lead list hopper deletion (Thanks Vic Jolin) +# 60322-1030 - Added super debug output +# 60418-0947 - Added lead filter per campaign +# 60509-1416 - Rewrite of local_call_time functions +# 60511-1150 - Added inserts into vicidial_campaign_stats table +# 60609-1451 - Added ability to filter by DNC list vicidial_dnc +# 60614-1159 - Added campaign lead recycling ability +# + +# constants +$DB=0; # Debug flag, set to 0 for no debug messages, On an active system this will generate lots of lines of output per minute +$US='__'; +$MT[0]=''; +#$vicidial_hopper='TEST_vicidial_hopper'; # for testing +$vicidial_hopper='vicidial_hopper'; + +# options +$insert_auto_CB_to_hopper = 1; # set to 1 to automatically insert ANYONE callbacks into the hopper + + +($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); +$year = ($year + 1900); +$mon++; +if ($mon < 10) {$mon = "0$mon";} +if ($mday < 10) {$mday = "0$mday";} +if ($hour < 10) {$Fhour = "0$hour";} +if ($min < 10) {$min = "0$min";} +if ($sec < 10) {$sec = "0$sec";} +$now_date = "$year-$mon-$mday $hour:$min:$sec"; +$VDL_date = "$year-$mon-$mday 00:00:01"; + +if (!$VDHLOGfile) {$VDHLOGfile = "/home/cron/hopper.$year-$mon-$mday";} + +### begin parsing run-time options ### +if (length($ARGV[0])>1) +{ + $i=0; + while ($#ARGV >= $i) + { + $args = "$args $ARGV[$i]"; + $i++; + } + + if ($args =~ /--help/i) + { + print "allowed run time options(must stay in this order):\n [--debug] = debug\n [--debugX] = super debug\n [--dbgmt] = show GMT offset of records as they are inserted into hopper\n [-t] = test\n [--level=XXX] = force a hopper_level of XXX\n [--campaign=XXX] = run for campaign XXX only\n\n"; + } + else + { + if ($args =~ /--campaign=/i) + { + # print "\n|$ARGS|\n\n"; + @data_in = split(/--campaign=/,$args); + $CLIcampaign = $data_in[1]; + } + else + {$CLIcampaign = '';} + if ($args =~ /--level=/i) + { + @data_in = split(/--level=/,$args); + $CLIlevel = $data_in[1]; + $CLIlevel =~ s/ .*$//gi; + $CLIlevel =~ s/\D//gi; + print "\n-----HOPPER LEVEL OVERRIDE: $CLIlevel -----\n\n"; + } + else + {$CLIlevel = '';} + if ($args =~ /--debug/i) + { + $DB=1; + print "\n----- DEBUG -----\n\n"; + } + if ($args =~ /--debugX/i) + { + $DBX=1; + print "\n----- SUPER DEBUG -----\n\n"; + } + if ($args =~ /--dbgmt/i) + { + $DB_show_offset=1; + print "\n-----DEBUG GMT -----\n\n"; + } + if ($args =~ /-t/i) + { + $T=1; $TEST=1; + print "\n-----TESTING -----\n\n"; + } + if ($args =~ /--wipe-hopper-clean/i) + { + $wipe_hopper_clean=1; + } + } +} +else +{ +print "no command line options set\n"; +} + +### Make sure this file is in a libs path or put the absolute path to it +require("/home/cron/AST_SERVER_conf.pl"); # local configuration file + +if (!$DB_port) {$DB_port='3306';} + +sleep(1); ### sleep for 5 seconds to stagger cron script load + +#use lib './lib', '../lib'; +use Net::MySQL; + + + my $dbhA = Net::MySQL->new(hostname => "$DB_server", database => "$DB_database", user => "$DB_user", password => "$DB_pass", port => "$DB_port") + or die "Couldn't connect to database: $DB_server - $DB_database\n"; + +### Grab Server values from the database +$stmtA = "SELECT local_gmt FROM servers where server_ip = '$server_ip';"; +$dbhA->query("$stmtA"); +if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $DBSERVER_GMT = "$record->[0]"; + if (length($DBSERVER_GMT)>0) {$SERVER_GMT = $DBSERVER_GMT;} + } + } + + +$secX = time(); + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($secX); + $LOCAL_GMT_OFF = $SERVER_GMT; + $LOCAL_GMT_OFF_STD = $SERVER_GMT; + if ($isdst) {$LOCAL_GMT_OFF++;} + + +$GMT_now = ($secX - ($LOCAL_GMT_OFF * 3600)); + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($GMT_now); + $mon++; + $year = ($year + 1900); + if ($mon < 10) {$mon = "0$mon";} + if ($mday < 10) {$mday = "0$mday";} + if ($hour < 10) {$hour = "0$hour";} + if ($min < 10) {$min = "0$min";} + if ($sec < 10) {$sec = "0$sec";} + + + if ($DB) {print "TIME DEBUG: $LOCAL_GMT_OFF_STD|$LOCAL_GMT_OFF|$isdst| GMT: $hour:$min\n";} + +if ($wipe_hopper_clean) + { + $stmtA = "DELETE from $vicidial_hopper;"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if ($DB) {print "Hopper Wiped Clean: $affected_rows\n";} + $event_string = "|HOPPER WIPE CLEAN|"; + &event_logger; + + exit; + } + +### Delete leads from inactive lists if there are any +$stmtA = "SELECT * FROM vicidial_lists where active='N';"; +if ($DB) {print $stmtA;} +$inactive_lists=''; +$inactive_lists_count=0; +$dbhA->query("$stmtA"); +if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $inactive_list = $record->[0]; + $inactive_lists .= "'$inactive_list',"; + $inactive_lists_count++; + } + } +if ($DB) {print "Inactive Lists: $inactive_lists_count\n";} + +if ($inactive_lists_count > 0) + { + chop($inactive_lists); + $stmtA = "DELETE from $vicidial_hopper where list_id IN($inactive_lists);"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if ($DB) {print "Inactive List Leads Deleted: $affected_rows |$stmtA|\n";} + $event_string = "|INACTIVE LIST DEL|$affected_rows|"; + &event_logger; + } + + +### BEGIN Change CBHOLD status leads to CALLBK if their vicidial_callbacks time has passed +$stmtA = "SELECT count(*) FROM vicidial_callbacks where callback_time <= '$now_date' and status='ACTIVE';"; +$dbhA->query("$stmtA"); +if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $CBHOLD_count = "$record->[0]"; + } + } + + if ($DB) {print "CALLBACK HOLD: $CBHOLD_count|$stmtA|\n";} + +if ($CBHOLD_count > 0) + { + $update_leads=''; + $stmtA = "SELECT vicidial_callbacks.lead_id,recipient,campaign_id,vicidial_callbacks.list_id,gmt_offset_now FROM vicidial_callbacks,vicidial_list where callback_time <= '$now_date' and vicidial_callbacks.status='ACTIVE' and vicidial_callbacks.lead_id=vicidial_list.lead_id;"; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $cbc=0; + $cba=0; + while ( $record = $iter->each) + { + $lead_ids[$cbc] = $record->[0]; + $recipient = $record->[1]; + $update_leads .= "'$lead_ids[$cbc]',"; + if ($recipient == 'ANYONE') + { + $CA_lead_id[$cba] = $record->[0]; + $CA_campaign_id[$cba] = $record->[2]; + $CA_list_id[$cba] = $record->[3]; + $CA_gmt_offset_now[$cba] = $record->[4]; + $cba++; + } + $cbc++; + } + } + if ($cbc > 0) + { + chop($update_leads); + + $stmtA = "UPDATE vicidial_list set status='CALLBK', called_since_last_reset='N' where lead_id IN($update_leads);"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if ($DB) {print "Scheduled Callbacks Activated: $affected_rows\n";} + $event_string = "|CALLBACKS LISTACT|$affected_rows|"; + &event_logger; + + $stmtA = "UPDATE vicidial_callbacks set status='LIVE' where lead_id IN($update_leads);"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if ($DB) {print "Scheduled Callbacks Activated: $affected_rows\n";} + $event_string = "|CALLBACKS CB ACT |$affected_rows|"; + &event_logger; + + } + ### INSERT ANYONE CALLBACKS INTO HOPPER DIRECTLY ### + if ( ($cba > 0) && ($insert_auto_CB_to_hopper) ) + { + if ($DB) {print "ANYONE Scheduled Callbacks Inserted into hopper: $cba\n";} + $event_string = "|ANYONE CB HOPPER |$cba|"; + &event_logger; + $CAu=0; + foreach(@CA_lead_id) + { + $stmtA = "INSERT INTO $vicidial_hopper SET lead_id='$CA_lead_id[$CAu]',campaign_id='$CA_campaign_id[$CAu]',list_id='$CA_list_id[$CAu]',gmt_offset_now='$CA_gmt_offset_now[$CAu]';"; + $dbhA->query("$stmtA"); + $CAu++; + } + } + } +### END Change CBHOLD status leads to CALLBK if their vicidial_callbacks time has passed + + + +@campaign_id=@MT; + +if ($CLIcampaign) + { + $stmtA = "SELECT * from vicidial_campaigns where campaign_id='$CLIcampaign'"; + } +else + { + $stmtA = "SELECT * from vicidial_campaigns where active='Y'"; + } + +$dbhA->query("$stmtA"); +if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_count=0; + while ( $record = $iter->each) + { + $campaign_id[$rec_count] = "$record->[0]"; + $dial_status_a[$rec_count] = "$record->[3]"; + $dial_status_b[$rec_count] = "$record->[4]"; + $dial_status_c[$rec_count] = "$record->[5]"; + $dial_status_d[$rec_count] = "$record->[6]"; + $dial_status_e[$rec_count] = "$record->[7]"; + $lead_order[$rec_count] = "$record->[8]"; + if (!$CLIlevel) + {$hopper_level[$rec_count] = "$record->[13]";} + else + {$hopper_level[$rec_count] = "$CLIlevel";} + $local_call_time[$rec_count] = "$record->[16]"; + $lead_filter_id[$rec_count] = "$record->[35]"; + $use_internal_dnc[$rec_count] = "$record->[43]"; + $rec_count++; + } + } + +$i=0; +foreach(@campaign_id) + { + ### close out MySQL connection and re-connect to start new connection ### +# $dbhA->close(); +# my $dbhA = ''; + + ### Make sure this file is in a libs path or put the absolute path to it +# require("/home/cron/AST_SERVER_conf.pl"); # local configuration file +# if (!$DB_port) {$DB_port='3306';} +# use Net::MySQL; + +# my $dbhA = Net::MySQL->new(hostname => "$DB_server", database => "$DB_database", user => "$DB_user", password => "$DB_pass", port => "$DB_port") +# or die "Couldn't connect to database: $DB_server - $DB_database\n"; + + + $VCSdialable_leads=0; + $VCScalls_today=0; + $VCSdrops_today=0; + $VCSdrops_today_pct=0; + $vicidial_log = 'vicidial_log'; + + $stmtA = "SELECT dialable_leads from vicidial_campaign_stats where campaign_id='$campaign_id[$i]';"; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_count=0; + while ( $record = $iter->each) + { + $VCSdialable_leads = "$record->[0]"; + } + } + $stmtA = "SELECT count(*) from $vicidial_log where campaign_id='$campaign_id[$i]' and call_date > '$VDL_date';"; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_count=0; + while ( $record = $iter->each) + { + $VCScalls_today = "$record->[0]"; + } + } + if ($VCScalls_today > 0) + { + $stmtA = "SELECT count(*) from $vicidial_log where campaign_id='$campaign_id[$i]' and call_date > '$VDL_date' and status IN('DROP','XDROP');"; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_count=0; + while ( $record = $iter->each) + { + $VCSdrops_today = "$record->[0]"; + if ($VCSdrops_today > 0) + { + $VCSdrops_today_pct = ( ($VCSdrops_today / $VCScalls_today) * 100 ); + $VCSdrops_today_pct = sprintf("%.2f", $VCSdrops_today_pct); + } + } + } + } + + $stmtA = "UPDATE vicidial_campaign_stats SET calls_today='$VCScalls_today',drops_today='$VCSdrops_today',drops_today_pct='$VCSdrops_today_pct' where campaign_id='$campaign_id[$i]';"; + $dbhA->query("$stmtA"); + + ##### BEGIN calculate what gmt_offset_now values are within the allowed local_call_time setting ### + $g=0; + $p='13'; + $GMT_gmt[0] = ''; + $GMT_hour[0] = ''; + $GMT_day[0] = ''; + if ($DBX) {print "\n |GMT-DAY-HOUR| ";} + while ($p > -13) + { + $pzone = ($GMT_now + ($p * 3600)); + ($psec,$pmin,$phour,$pmday,$pmon,$pyear,$pday,$pyday,$pisdst) = localtime($pzone); + $phour=($phour * 100); + $tz = sprintf("%.2f", $p); + $GMT_gmt[$g] = "$tz"; + $GMT_day[$g] = "$pday"; + $GMT_hour[$g] = ($phour + $pmin); + $p = ($p - 0.25); + if ($DBX) {print "|$GMT_gmt[$g]-$GMT_day[$g]-$GMT_hour[$g]|";} + $g++; + } + if ($DBX) {print "\n";} + + $stmtA = "SELECT * FROM vicidial_call_times where call_time_id='$local_call_time[$i]';"; + if ($DBX) {print " |$stmtA|\n";} + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $Gct_default_start = "$record->[3]"; + $Gct_default_stop = "$record->[4]"; + $Gct_sunday_start = "$record->[5]"; + $Gct_sunday_stop = "$record->[6]"; + $Gct_monday_start = "$record->[7]"; + $Gct_monday_stop = "$record->[8]"; + $Gct_tuesday_start = "$record->[9]"; + $Gct_tuesday_stop = "$record->[10]"; + $Gct_wednesday_start = "$record->[11]"; + $Gct_wednesday_stop = "$record->[12]"; + $Gct_thursday_start = "$record->[13]"; + $Gct_thursday_stop = "$record->[14]"; + $Gct_friday_start = "$record->[15]"; + $Gct_friday_stop = "$record->[16]"; + $Gct_saturday_start = "$record->[17]"; + $Gct_saturday_stop = "$record->[18]"; + $Gct_state_call_times = "$record->[19]"; + } + } + + $ct_states = ''; + $ct_state_gmt_SQL = ''; + $del_state_gmt_SQL = ''; + $ct_srs=0; + $b=0; + if (length($Gct_state_call_times)>2) + { + @state_rules = split(/\|/,$Gct_state_call_times); + $ct_srs = ($#state_rules - 2); + } + while($ct_srs >= $b) + { + if (length($state_rules[$b])>1) + { + $stmtA = "SELECT * from vicidial_state_call_times where state_call_time_id='$state_rules[$b]';"; + if ($DBX) {print " |$stmtA|\n";} + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $Gstate_call_time_id = "$record->[0]"; + $Gstate_call_time_state = "$record->[1]"; + $Gsct_default_start = "$record->[4]"; + $Gsct_default_stop = "$record->[5]"; + $Gsct_sunday_start = "$record->[6]"; + $Gsct_sunday_stop = "$record->[7]"; + $Gsct_monday_start = "$record->[8]"; + $Gsct_monday_stop = "$record->[9]"; + $Gsct_tuesday_start = "$record->[10]"; + $Gsct_tuesday_stop = "$record->[11]"; + $Gsct_wednesday_start = "$record->[12]"; + $Gsct_wednesday_stop = "$record->[13]"; + $Gsct_thursday_start = "$record->[14]"; + $Gsct_thursday_stop = "$record->[15]"; + $Gsct_friday_start = "$record->[16]"; + $Gsct_friday_stop = "$record->[17]"; + $Gsct_saturday_start = "$record->[18]"; + $Gsct_saturday_stop = "$record->[19]"; + $ct_states .="'$Gstate_call_time_state',"; + } + } + + $r=0; + $state_gmt=''; + $del_state_gmt=''; + while($r < $g) + { + if ($GMT_day[$r]==0) #### Sunday local time + { + if (($Gsct_sunday_start==0) and ($Gsct_sunday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gsct_default_start) and ($GMT_hour[$r]<$Gsct_default_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gsct_sunday_start) and ($GMT_hour[$r]<$Gsct_sunday_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==1) #### Monday local time + { + if (($Gsct_monday_start==0) and ($Gsct_monday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gsct_default_start) and ($GMT_hour[$r]<$Gsct_default_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gsct_monday_start) and ($GMT_hour[$r]<$Gsct_monday_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==2) #### Tuesday local time + { + if (($Gsct_tuesday_start==0) and ($Gsct_tuesday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gsct_default_start) and ($GMT_hour[$r]<$Gsct_default_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gsct_tuesday_start) and ($GMT_hour[$r]<$Gsct_tuesday_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==3) #### Wednesday local time + { + if (($Gsct_wednesday_start==0) and ($Gsct_wednesday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gsct_default_start) and ($GMT_hour[$r]<$Gsct_default_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gsct_wednesday_start) and ($GMT_hour[$r]<$Gsct_wednesday_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==4) #### Thursday local time + { + if (($Gsct_thursday_start==0) and ($Gsct_thursday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gsct_default_start) and ($GMT_hour[$r]<$Gsct_default_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gsct_thursday_start) and ($GMT_hour[$r]<$Gsct_thursday_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==5) #### Friday local time + { + if (($Gsct_friday_start==0) and ($Gsct_friday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gsct_default_start) and ($GMT_hour[$r]<$Gsct_default_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gsct_friday_start) and ($GMT_hour[$r]<$Gsct_friday_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==6) #### Saturday local time + { + if (($Gsct_saturday_start==0) and ($Gsct_saturday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gsct_default_start) and ($GMT_hour[$r]<$Gsct_default_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gsct_saturday_start) and ($GMT_hour[$r]<$Gsct_saturday_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + } + $r++; + } + $state_gmt = "$state_gmt'99'"; + $del_state_gmt = "$del_state_gmt'99'"; + $ct_state_gmt_SQL .= "or (state='$Gstate_call_time_state' and gmt_offset_now IN($state_gmt)) "; + $del_state_gmt_SQL .= "or (state='$Gstate_call_time_state' and gmt_offset_now IN($del_state_gmt)) "; + } + + $b++; + } + if (length($ct_states)>2) + { + $ct_states =~ s/,$//gi; + $ct_statesSQL = "and state NOT IN($ct_states)"; + } + else + { + $ct_statesSQL = ""; + } + + $r=0; + $default_gmt=''; + $del_default_gmt=''; + while($r < $g) + { + if ($GMT_day[$r]==0) #### Sunday local time + { + if (($Gct_sunday_start==0) and ($Gct_sunday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gct_default_start) and ($GMT_hour[$r]<$Gct_default_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gct_sunday_start) and ($GMT_hour[$r]<$Gct_sunday_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==1) #### Monday local time + { + if (($Gct_monday_start==0) and ($Gct_monday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gct_default_start) and ($GMT_hour[$r]<$Gct_default_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gct_monday_start) and ($GMT_hour[$r]<$Gct_monday_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==2) #### Tuesday local time + { + if (($Gct_tuesday_start==0) and ($Gct_tuesday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gct_default_start) and ($GMT_hour[$r]<$Gct_default_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gct_tuesday_start) and ($GMT_hour[$r]<$Gct_tuesday_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==3) #### Wednesday local time + { + if (($Gct_wednesday_start==0) and ($Gct_wednesday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gct_default_start) and ($GMT_hour[$r]<$Gct_default_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gct_wednesday_start) and ($GMT_hour[$r]<$Gct_wednesday_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==4) #### Thursday local time + { + if (($Gct_thursday_start==0) and ($Gct_thursday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gct_default_start) and ($GMT_hour[$r]<$Gct_default_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gct_thursday_start) and ($GMT_hour[$r]<$Gct_thursday_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==5) #### Friday local time + { + if (($Gct_friday_start==0) and ($Gct_friday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gct_default_start) and ($GMT_hour[$r]<$Gct_default_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gct_friday_start) and ($GMT_hour[$r]<$Gct_friday_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==6) #### Saturday local time + { + if (($Gct_saturday_start==0) and ($Gct_saturday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gct_default_start) and ($GMT_hour[$r]<$Gct_default_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gct_saturday_start) and ($GMT_hour[$r]<$Gct_saturday_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + } + $r++; + } + + $default_gmt = "$default_gmt'99'"; + $del_default_gmt = "$del_default_gmt'99'"; + $all_gmtSQL = "(gmt_offset_now IN($default_gmt) $ct_statesSQL) $ct_state_gmt_SQL"; + $del_gmtSQL = "(gmt_offset_now IN($del_default_gmt) $ct_statesSQL) $del_state_gmt_SQL"; + + ##### END calculate what gmt_offset_now values are within the allowed local_call_time setting ### + + ##### BEGIN lead recycling parsing and prep ### + + $stmtA = "SELECT * from vicidial_lead_recycle where campaign_id='$campaign_id[$i]' and active='Y';"; + $dbhA->query("$stmtA"); + $rec_ct=0; + if ($dbhA->has_selected_record) + { + @recycle_status=@MT; + @recycle_delay=@MT; + @recycle_maximum=@MT; + @RSQLdate=@MT; + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $recycle_status[$rec_ct] = $record->[2]; + $recycle_delay[$rec_ct] = $record->[3]; + $recycle_maximum[$rec_ct] = $record->[4]; + $rec_ct++; + } + } + + if ($rec_ct > 0) + { + $rc=0; + $recycle_SQL = "( "; + while($rc < $rec_ct) + { + $secX = time(); + $Rtarget = ($secX - $recycle_delay[$rc]); + ($Rsec,$Rmin,$Rhour,$Rmday,$Rmon,$Ryear,$Rwday,$Ryday,$Risdst) = localtime($Rtarget); + $Ryear = ($Ryear + 1900); + $Rmon++; + if ($Rmon < 10) {$Rmon = "0$Rmon";} + if ($Rmday < 10) {$Rmday = "0$Rmday";} + if ($Rhour < 10) {$Rhour = "0$Rhour";} + if ($Rmin < 10) {$Rmin = "0$Rmin";} + if ($Rsec < 10) {$Rsec = "0$Rsec";} + $RSQLdate[$rc] = "$Ryear-$Rmon-$Rmday $Rhour:$Rmin:$Rsec"; + $Y=1; + $recycle_Y = "'Y'"; + while ($Y < $recycle_maximum[$rc]) + { + $recycle_Y .= ",'Y$Y'"; + $Y++; + } + + if ($rc > 0) {$recycle_SQL .= " or ";} + + $recycle_SQL .= "( (called_since_last_reset IN($recycle_Y)) and (status='$recycle_status[$rc]') and (modify_date < \"$RSQLdate[$rc]\") )"; + + if ($DBX) {print "RECYCLE: |$campaign_id[$i]|$recycle_status[$rc]|$recycle_delay[$rc]|$recycle_maximum[$rc]|$RSQLdate[$rc]|\n";} + $rc++; + } + + $recycle_SQL .= " )"; + + if ($DBX) {print "RECYCLE SQL: |$recycle_SQL|\n";} + } + ##### END lead recycling parsing and prep ### + + if ($DB) {print "Starting hopper run for $campaign_id[$i] campaign- GMT: $local_call_time[$i] HOPPER: $hopper_level[$i] \n";} + + ### Delete the DONE leads if there are any + $stmtA = "DELETE from $vicidial_hopper where campaign_id='$campaign_id[$i]' and status IN('DONE');"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if ($DB) {print " hopper DONE cleared: $affected_rows\n";} + if ($DBX) {print " |$stmtA|\n";} + + ### Delete the leads that are out of GMT time range if there are any + $stmtA = "DELETE from $vicidial_hopper where campaign_id='$campaign_id[$i]' and ($del_gmtSQL);"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if ($DB) {print " hopper GMT BAD cleared: $affected_rows\n";} + if ($DBX) {print " |$stmtA|\n";} + + ### Find out how many leads are in the hopper from a specific campaign + $hopper_ready_count=0; + $stmtA = "SELECT count(*) from $vicidial_hopper where campaign_id='$campaign_id[$i]' and status='READY';"; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_countA=0; + while ( $record = $iter->each) + { + $hopper_ready_count = $record->[0]; + if ($DB) {print " hopper READY count: $hopper_ready_count\n";} + if ($DBX) {print " |$stmtA|\n";} + $rec_countA++; + } + } + $event_string = "|$campaign_id[$i]|$hopper_level[$i]|$hopper_ready_count|$local_call_time[$i]||"; + &event_logger; + + ##### IF hopper level is below set minimum, then try to add more leads ##### + if ($hopper_ready_count < $hopper_level[$i]) + { + if ($DB) {print " hopper too low ($hopper_ready_count|$hopper_level[$i]) starting hopper dump\n";} + + ### Get list of the lists in the campaign ### + $stmtA = "SELECT list_id FROM vicidial_lists where campaign_id='$campaign_id[$i]' and active='Y';"; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_countLISTS=0; + $camp_lists = ''; + while ( $record = $iter->each) + { + $camp_lists .= "'$record->[0]',"; + $rec_countLISTS++; + } + chop($camp_lists); + } + if ($DB) {print " campaign lists count: $rec_countLISTS | $camp_lists\n";} + if ($DBX) {print " |$stmtA|\n";} + + if ( ($lead_filter_id[$i] !~ /NONE/) && (length($lead_filter_id[$i])>0) ) + { + ### Get SQL of lead filter for the campaign ### + $stmtA = "SELECT lead_filter_sql FROM vicidial_lead_filters where lead_filter_id='$lead_filter_id[$i]';"; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $lead_filter_sql[$i] = "$record->[0]"; + } + } + $lead_filter_sql[$i] =~ s/^and|and$|^or|or$|^ and|and $|^ or|or $//gi; + $lead_filter_sql[$i] = "and $lead_filter_sql[$i]"; + if ($DB) {print " campaign lists count: $rec_countLISTS | $camp_lists\n";} + if ($DB) {print " lead filter $lead_filter_id[$i] defined for $campaign_id[$i]\n";} + if ($DBX) {print " |$lead_filter_sql[$i]|\n";} + } + else + { + $lead_filter_sql[$i] = ''; + if ($DB) {print " no lead filter defined for campaign: $campaign_id[$i]\n";} + if ($DBX) {print " |$lead_filter_id[$i]|\n";} + } + + $stmtA = "SELECT count(*) FROM vicidial_list where called_since_last_reset='N' and status IN('$dial_status_a[$i]','$dial_status_b[$i]','$dial_status_c[$i]','$dial_status_d[$i]','$dial_status_e[$i]') and list_id IN($camp_lists) and ($all_gmtSQL) $lead_filter_sql[$i];"; + if ($DBX) {print " |$stmtA|\n";} + $dbhA->query("$stmtA"); + $campaign_leads_to_call=0; + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $campaign_leads_to_call = "$record->[0]"; + if ($DB) {print " leads to call count: $campaign_leads_to_call\n";} + if ($DBX) {print " |$stmtA|\n";} + } + } + if ($lead_order[$i] =~ /DOWN COUNT 2nd NEW|DOWN COUNT 3rd NEW|DOWN COUNT 4th NEW/) + { + $stmtA = "SELECT count(*) FROM vicidial_list where called_since_last_reset='N' and status IN('NEW') and list_id IN($camp_lists) and ($all_gmtSQL) $lead_filter_sql[$i];"; + $dbhA->query("$stmtA"); + $NEW_campaign_leads_to_call=0; + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $NEW_campaign_leads_to_call = "$record->[0]"; + if ($DB) {print " NEW leads to call count: $NEW_campaign_leads_to_call\n";} + if ($DBX) {print " |$stmtA|\n";} + } + } + } + + ##### IF no NEW leads to be called, error out of this campaign ##### + if ( ($lead_order[$i] =~ /DOWN COUNT 2nd NEW|DOWN COUNT 3rd NEW|DOWN COUNT 4th NEW/) && ($NEW_campaign_leads_to_call > 0) ) {$GOOD=1;} + else + { + if ($DB) {print " ERROR CANNOT ADD ANY NEW LEADS TO HOPPER\n";} + } + + ##### IF no leads to be called, error out of this campaign ##### + if ($campaign_leads_to_call < 1) + { + if ($DB) {print " ERROR CANNOT ADD ANY LEADS TO HOPPER\n";} + if ($VCSdialable_leads > 0) + { + $stmtA = "UPDATE vicidial_campaign_stats SET dialable_leads='0' where campaign_id='$campaign_id[$i]';"; + $dbhA->query("$stmtA"); + } + } + else + { + if ($VCSdialable_leads != $campaign_leads_to_call) + { + $stmtA = "UPDATE vicidial_campaign_stats SET dialable_leads='$campaign_leads_to_call' where campaign_id='$campaign_id[$i]';"; + $dbhA->query("$stmtA"); + } + if ($DB) {print " Getting Leads to add to hopper\n";} + ### grab leads already in hopper so we don't duplicate + $stmtA = "SELECT lead_id FROM $vicidial_hopper where campaign_id='$campaign_id[$i]';"; + if ($DBX) {print " |$stmtA|\n";} + $dbhA->query("$stmtA"); + $rec_countLISTS=0; + $lead_id_lists = ''; + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $lead_id_lists .= "'$record->[0]',"; + $rec_countLISTS++; + } + $lead_id_lists .= "'0'"; + } + + $order_stmt=''; + $NEW_count = 0; + $NEW_level = 0; + $OTHER_level = $hopper_level[$i]; + if ($lead_order[$i] eq "DOWN") {$order_stmt = 'order by lead_id asc';} + if ($lead_order[$i] eq "UP") {$order_stmt = 'order by lead_id desc';} + if ($lead_order[$i] eq "UP LAST NAME") {$order_stmt = 'order by last_name desc, lead_id asc';} + if ($lead_order[$i] eq "DOWN LAST NAME") {$order_stmt = 'order by last_name, lead_id asc';} + if ($lead_order[$i] eq "UP PHONE") {$order_stmt = 'order by phone_number desc, lead_id asc';} + if ($lead_order[$i] eq "DOWN PHONE") {$order_stmt = 'order by phone_number, lead_id asc';} + if ($lead_order[$i] eq "UP COUNT") {$order_stmt = 'order by called_count desc, lead_id asc';} + if ($lead_order[$i] eq "DOWN COUNT") {$order_stmt = 'order by called_count, lead_id asc';} + if ($lead_order[$i] eq "DOWN COUNT 2nd NEW") {$NEW_count = 2;} + if ($lead_order[$i] eq "DOWN COUNT 3rd NEW") {$NEW_count = 3;} + if ($lead_order[$i] eq "DOWN COUNT 4th NEW") {$NEW_count = 4;} + + ### BEGIN recycle grab leads ### + if ($rec_ct > 0) + { + if ($DB) {print " looking for RECYCLE leads, maximum of 100\n";} + + $stmtA = "SELECT lead_id,list_id,gmt_offset_now,phone_number,state FROM vicidial_list where $recycle_SQL and list_id IN($camp_lists) and lead_id NOT IN($lead_id_lists) and ($all_gmtSQL) $lead_filter_sql[$i] limit 100;"; + if ($DBX) {print " |$stmtA|\n";} + $REC_rec_countLEADS=0; + @REC_leads_to_hopper=@MT; + @REC_lists_to_hopper=@MT; + @REC_phone_to_hopper=@MT; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $REC_leads_to_hopper[$REC_rec_countLEADS] = "$record->[0]"; + $REC_lists_to_hopper[$REC_rec_countLEADS] = "$record->[1]"; + $REC_gmt_to_hopper[$REC_rec_countLEADS] = "$record->[2]"; + $REC_phone_to_hopper[$REC_rec_countLEADS] = "$record->[3]"; + $REC_state_to_hopper[$REC_rec_countLEADS] = "$record->[4]"; + if ($DB_show_offset) {print "LEAD_ADD: $record->[2] $record->[3] $record->[4]\n";} + $REC_rec_countLEADS++; + } + } + if ($DB) {print " RECYCLE leads to call count: $REC_rec_countLEADS\n";} + if ($DBX) {print " |$stmtA|\n";} + } + ### END recycle grab leads ### + + if ($NEW_count > 0) + { + $NEW_level = int($hopper_level[$i] / $NEW_count); + $OTHER_level = ($hopper_level[$i] - $NEW_level); + $order_stmt = 'order by called_count, lead_id asc'; + if ($DB) {print " looking for $NEW_level NEW leads mixed in with $OTHER_level other leads\n";} + + $stmtA = "SELECT lead_id,list_id,gmt_offset_now,phone_number,state FROM vicidial_list where called_since_last_reset='N' and status IN('NEW') and list_id IN($camp_lists) and lead_id NOT IN($lead_id_lists) and ($all_gmtSQL) $lead_filter_sql[$i] $order_stmt limit $NEW_level;"; + if ($DBX) {print " |$stmtA|\n";} + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $NEW_rec_countLEADS=0; + @NEW_leads_to_hopper=@MT; + @NEW_lists_to_hopper=@MT; + @NEW_phone_to_hopper=@MT; + while ( $record = $iter->each) + { + $NEW_leads_to_hopper[$NEW_rec_countLEADS] = "$record->[0]"; + $NEW_lists_to_hopper[$NEW_rec_countLEADS] = "$record->[1]"; + $NEW_gmt_to_hopper[$NEW_rec_countLEADS] = "$record->[2]"; + $NEW_phone_to_hopper[$NEW_rec_countLEADS] = "$record->[3]"; + $NEW_state_to_hopper[$NEW_rec_countLEADS] = "$record->[4]"; + if ($DB_show_offset) {print "LEAD_ADD: $record->[2] $record->[3] $record->[4]\n";} + $NEW_rec_countLEADS++; + } + } + + } + + if ($DB) {print " lead call order: $order_stmt\n";} + $stmtA = "SELECT lead_id,list_id,gmt_offset_now,phone_number,state FROM vicidial_list where called_since_last_reset='N' and status IN('$dial_status_a[$i]','$dial_status_b[$i]','$dial_status_c[$i]','$dial_status_d[$i]','$dial_status_e[$i]') and list_id IN($camp_lists) and lead_id NOT IN($lead_id_lists) and ($all_gmtSQL) $lead_filter_sql[$i] $order_stmt limit $OTHER_level;"; + if ($DBX) {print " |$stmtA|\n";} + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_countLEADS=0; $NEW_dec=99; $NEW_in=0; + @leads_to_hopper=@MT; + @lists_to_hopper=@MT; + @gmt_to_hopper=@MT; + @state_to_hopper=@MT; + @phone_to_hopper=@MT; + while ( $record = $iter->each) + { + if ( ($NEW_count > 0) && ($NEW_rec_countLEADS > $NEW_in) ) + { + if ($DB_show_offset) {print "NEW_COUNT: $NEW_count|$NEW_dec|$NEW_in|$NEW_rec_countLEADS\n";} + if ($NEW_count > $NEW_dec) + { + $NEW_dec++; + } + else + { + $leads_to_hopper[$rec_countLEADS] = "$NEW_leads_to_hopper[$NEW_in]"; + $lists_to_hopper[$rec_countLEADS] = "$NEW_lists_to_hopper[$NEW_in]"; + $gmt_to_hopper[$rec_countLEADS] = "$NEW_gmt_to_hopper[$NEW_in]"; + $state_to_hopper[$rec_countLEADS] = "$NEW_state_to_hopper[$NEW_in]"; + $phone_to_hopper[$rec_countLEADS] = "$NEW_phone_to_hopper[$NEW_in]"; + if ($DB_show_offset) {print "LEAD_ADD: $NEW_leads_to_hopper[$NEW_in] $NEW_phone_to_hopper[$NEW_in]\n";} + $rec_countLEADS++; + $NEW_in++; + $NEW_dec=2; + } + } + if ($REC_rec_countLEADS > $REC_insert_count) + { + $leads_to_hopper[$rec_countLEADS] = "$REC_leads_to_hopper[$REC_insert_count]"; + $lists_to_hopper[$rec_countLEADS] = "$REC_lists_to_hopper[$REC_insert_count]"; + $gmt_to_hopper[$rec_countLEADS] = "$REC_gmt_to_hopper[$REC_insert_count]"; + $state_to_hopper[$rec_countLEADS] = "$REC_state_to_hopper[$REC_insert_count]"; + $phone_to_hopper[$rec_countLEADS] = "$REC_phone_to_hopper[$REC_insert_count]"; + $rec_countLEADS++; + $REC_insert_count++; + } + $leads_to_hopper[$rec_countLEADS] = "$record->[0]"; + $lists_to_hopper[$rec_countLEADS] = "$record->[1]"; + $gmt_to_hopper[$rec_countLEADS] = "$record->[2]"; + $state_to_hopper[$rec_countLEADS] = "$record->[4]"; + $phone_to_hopper[$rec_countLEADS] = "$record->[3]"; + if ($DB_show_offset) {print "LEAD_ADD: $record->[2] $record->[3] $record->[4]\n";} + $rec_countLEADS++; + } + } + + if ($DB) {print " Adding to hopper: $rec_countLEADS\n";} + $event_string = "|$campaign_id[$i]|Added to hopper $rec_countLEADS|"; + &event_logger; + + $h=0; + foreach(@leads_to_hopper) + { + if ($leads_to_hopper[$h] != '0') + { + $DNClead=0; + if ($use_internal_dnc[$i] =~ /Y/) + { + if ($DB) {print " Doinbg DNC Check: $phone_to_hopper[$h]\n";} + $stmtA = "SELECT count(*) from vicidial_dnc where phone_number='$phone_to_hopper[$h]';"; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_count=0; + while ( $record = $iter->each) + { + $DNClead = "$record->[0]"; + } + } + if ($DNClead != '0') + { + $stmtA = "UPDATE vicidial_list SET status='DNCL' where lead_id='$leads_to_hopper[$h]';"; + $dbhA->query("$stmtA"); + if ($DB) {print "Flagging DNC lead: $leads_to_hopper[$h] $phone_to_hopper[$h]\n";} + } + } + if ($DNClead == '0') + { + $stmtA = "INSERT INTO $vicidial_hopper (lead_id,campaign_id,status,user,list_id,gmt_offset_now,state) values('$leads_to_hopper[$h]','$campaign_id[$i]','READY','','$lists_to_hopper[$h]','$gmt_to_hopper[$h]','$state_to_hopper[$h]');"; + $dbhA->query("$stmtA"); + } + } + $h++; + } + if ($DB) {print " DONE with this campaign\n";} + + } + } + + + $i++; + } + + +$dbhA->close; + +if($DB){print "DONE... Exiting... Goodbye... See you later... Really, I mean it :)\n";} + +exit; + + + +sub event_logger { + ### open the log file for writing ### + open(Lout, ">>$VDHLOGfile") + || die "Can't open $VDHLOGfile: $!\n"; + + print Lout "$now_date|$event_string|\n"; + + close(Lout); + +$event_string=''; +} + + diff --git a/AST_VDremote_agents.pl b/AST_VDremote_agents.pl new file mode 100644 index 00000000..a042effa --- /dev/null +++ b/AST_VDremote_agents.pl @@ -0,0 +1,493 @@ +#!/usr/bin/perl +# +# AST_VDremote_agents.pl version 0.1 +# +# DESCRIPTION: +# uses Net::MySQL to keep remote agents logged in to the VICIDIAL system +# +# SUMMARY: +# This program was designed for people using the Asterisk PBX with VICIDIAL +# +# For the client to use VICIDIAL with remote agents, this must always be running +# +# It is recommended that you run this program on the local Asterisk machine +# +# This script is to run perpetually querying every second to update the remote +# agents that should appear to be logged in so that the calls can be transferred +# out to them properly. +# +# It is good practice to keep this program running by placing the associated +# KEEPALIVE script running every minute to ensure this program is always running +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# +# changes: +# 50215-0954 - First version of script +# 50810-1615 - Added database server variable definitions lookup +# + +### begin parsing run-time options ### +if (length($ARGV[0])>1) +{ + $i=0; + while ($#ARGV >= $i) + { + $args = "$args $ARGV[$i]"; + $i++; + } + + if ($args =~ /--help/i) + { + print "allowed run time options:\n [-t] = test\n [-v] = verbose debug messages\n [--delay=XXX] = delay of XXX seconds per loop, default 2 seconds\n\n"; + } + else + { + if ($args =~ /--delay=/i) + { + @data_in = split(/--delay=/,$args); + $loop_delay = $data_in[1]; + print " LOOP DELAY OVERRIDE!!!!! = $loop_delay seconds\n\n"; + $loop_delay = ($loop_delay * 1000); + } + else + { + $loop_delay = '2000'; + } + if ($args =~ /-v/i) + { + $V=1; # Debug flag, set to 0 for no debug messages, On an active system this will generate hundreds of lines of output per minute + } + if ($args =~ /-t/i) + { + $TEST=1; + $T=1; + } + } +} +else +{ +print "no command line options set\n"; + $loop_delay = '2000'; + $V=1; +} +### end parsing run-time options ### + + +# constants +$US='__'; +$MT[0]=''; + +### Make sure this file is in a libs path or put the absolute path to it +require("/home/cron/AST_SERVER_conf.pl"); # local configuration file + +if (!$DB_port) {$DB_port='3306';} + +use lib './lib', '../lib'; +use Time::HiRes ('gettimeofday','usleep','sleep'); # necessary to have perl sleep command of less than one second +use Net::MySQL; + + ### connect to MySQL database defined in the AST_SERVER_conf.pl file + my $dbhA = Net::MySQL->new(hostname => "$DB_server", database => "$DB_database", user => "$DB_user", password => "$DB_pass", port => "$DB_port") + or die "Couldn't connect to database: $DB_server - $DB_database\n"; + +### Grab Server values from the database +$stmtA = "SELECT local_gmt FROM servers where server_ip = '$server_ip';"; +$dbhA->query("$stmtA"); +if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $DBSERVER_GMT = "$record->[0]"; + if ($DBSERVER_GMT) {$SERVER_GMT = $DBSERVER_GMT;} + } + } + + + &get_time_now; # update time/date variables + + $event_string='PROGRAM STARTED||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||'; + &event_logger; # writes to the log and if debug flag is set prints to STDOUT + + + $event_string='LOGGED INTO MYSQL SERVER ON 1 CONNECTION|'; + &event_logger; + +$one_day_interval = 12; # 1 month loops for one year +while($one_day_interval > 0) +{ + + $endless_loop=5760000; # 30 days minutes at XXX seconds per loop + + while($endless_loop > 0) + { + &get_time_now; + + if ($endless_loop =~ /0$|5$/) + { + ### delete call records that are LIVE for over 10 minutes and last_update_time < '$PDtsSQLdate' + $stmtA = "DELETE FROM vicidial_live_agents where server_ip='$server_ip' and status IN('PAUSED') and extension LIKE \"R/%\""; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + + $event_string = "| lagged call vla agent DELETED $affected_rows"; + &event_logger; + + + $stmtA = "UPDATE vicidial_live_agents set status='INCALL', last_call_time='$SQLdate' where server_ip='$server_ip' and status IN('QUEUE') and extension LIKE \"R/%\""; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + + $event_string = "| QUEUEd call listing vla UPDATEd $affected_rows"; + &event_logger; + + #@psoutput = `/bin/ps -f --no-headers -A`; + @psoutput = `/bin/ps -o "%p %a" --no-headers -A`; + + $running_listen = 0; + + $i=0; + foreach (@psoutput) + { + chomp($psoutput[$i]); + + @psline = split(/\/usr\/bin\/perl /,$psoutput[$i]); + + if ($psline[1] =~ /AST_manager_li/) {$running_listen++;} + + $i++; + } + + if (!$running_listen) + { + $endless_loop=0; + $one_day_interval=0; + print "\nPROCESS KILLED NO LISTENER RUNNING... EXITING\n\n"; + } + + if($DB){print "checking to see if listener is dead |$running_listen|\n";} + } + + + + $user_counter=0; + @DBremote_user=@MT; + @DBremote_server_ip=@MT; + @DBremote_campaign=@MT; + @DBremote_conf_exten=@MT; + @DBremote_closer=@MT; + @DBremote_random=@MT; + @loginexistsRANDOM=@MT; + @loginexistsALL=@MT; + @VD_user=@MT; + @VD_extension=@MT; + @VD_status=@MT; + @VD_uniqueid=@MT; + @VD_callerid=@MT; + @VD_random=@MT; + ############################################################################### + ###### first grab all of the ACTIVE remote agents information from the database + ############################################################################### + $dbhA->query("SELECT * FROM vicidial_remote_agents where status IN('ACTIVE') and server_ip='$server_ip' order by user_start"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $user_start = "$record->[1]"; + $number_of_lines = "$record->[2]"; + $conf_exten = "$record->[4]"; + $campaign_id = "$record->[6]"; + $closer_campaigns = "$record->[7]"; + + $y=0; + while ($y < $number_of_lines) + { + $random = int( rand(9999999)) + 10000000; + $user_id = ($user_start + $y); + $DBremote_user[$user_counter] = "$user_id"; + $DBremote_server_ip[$user_counter] = "$server_ip"; + $DBremote_campaign[$user_counter] = "$campaign_id"; + $DBremote_conf_exten[$user_counter] = "$conf_exten"; + $DBremote_closer[$user_counter] = "$closer_campaigns"; + $DBremote_random[$user_counter] = "$random"; + + $y++; + $user_counter++; + } + + } + if ($V) {print STDERR "$user_counter live remote agents ACTIVE\n";} + } + + + ############################################################################### + ###### second traverse array of remote agents to be active and insert or update + ###### in vicidial_live_agents table + ############################################################################### + $h=0; + foreach(@DBremote_user) + { + if (length($DBremote_user[$h])>1) + { + + ### check to see if the record exists and only needs random number update + $dbhA->query("SELECT count(*) FROM vicidial_live_agents where user='$DBremote_user[$h]' and server_ip='$server_ip' and campaign_id='$DBremote_campaign[$h]' and conf_exten='$DBremote_conf_exten[$h]' and closer_campaigns='$DBremote_closer[$h]'"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $loginexistsRANDOM[$h] = "$record->[0]"; + } + } + if ($loginexistsRANDOM[$h] > 0) + { + $stmtA = "UPDATE vicidial_live_agents set random_id='$DBremote_random[$h]' where user='$DBremote_user[$h]' and server_ip='$server_ip' and campaign_id='$DBremote_campaign[$h]' and conf_exten='$DBremote_conf_exten[$h]' and closer_campaigns='$DBremote_closer[$h]'"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if ($V) {print STDERR "$DBremote_user[$h] $DBremote_campaign[$h] ONLY RANDOM ID UPDATE: $affected_rows\n";} + } + ### check if record for user on server exists at all in vicidial_live_agents + else + { + $dbhA->query("SELECT count(*) FROM vicidial_live_agents where user='$DBremote_user[$h]' and server_ip='$server_ip'"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $loginexistsALL[$h] = "$record->[0]"; + } + } + if ($loginexistsALL[$h] > 0) + { + $stmtA = "UPDATE vicidial_live_agents set random_id='$DBremote_random[$h]',campaign_id='$DBremote_campaign[$h]',conf_exten='$DBremote_conf_exten[$h]',closer_campaigns='$DBremote_closer[$h]', status='READY' where user='$DBremote_user[$h]' and server_ip='$server_ip'"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if ($V) {print STDERR "$DBremote_user[$h] ALL UPDATE: $affected_rows\n";} + } + ### no records exist so insert a new one + else + { + $stmtA = "INSERT INTO vicidial_live_agents (user,server_ip,conf_exten,extension,status,campaign_id,random_id,last_call_time,last_update_time,last_call_finish,closer_campaigns,channel,uniqueid,callerid) values('$DBremote_user[$h]','$server_ip','$DBremote_conf_exten[$h]','R/$DBremote_user[$h]','READY','$DBremote_campaign[$h]','$DBremote_random[$h]','$SQLdate','$tsSQLdate','$SQLdate','$DBremote_closer[$h]','','','')"; + $dbhA->query("$stmtA"); + if ($V) {print STDERR "$DBremote_user[$h] NEW INSERT\n";} + } + } + } + $h++; + } + + + ############################################################################### + ###### third validate that the calls that the vicidial_live_agents are on are not dead + ###### and if they are wipe out the values and set the agent record back to READY + ############################################################################### + $dbhA->query("SELECT user,extension,status,uniqueid,callerid FROM vicidial_live_agents where extension LIKE \"R/%\" and server_ip='$server_ip' and uniqueid > 10"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $z=0; + while ( $record = $iter->each) + { + $VDuser = "$record->[0]"; + $VDextension = "$record->[1]"; + $VDstatus = "$record->[2]"; + $VDuniqueid = "$record->[3]"; + $VDcallerid = "$record->[4]"; + $VDrandom = int( rand(9999999)) + 10000000; + + $VD_user[$z] = "$VDuser"; + $VD_extension[$z] = "$VDextension"; + $VD_status[$z] = "$VDstatus"; + $VD_uniqueid[$z] = "$VDuniqueid"; + $VD_callerid[$z] = "$VDcallerid"; + $VD_random[$z] = "$VDrandom"; + + $z++; + } + if ($V) {print STDERR "$z remote agents on calls\n";} + } + $z=0; + foreach(@VD_user) + { + $dbhA->query("SELECT count(*) FROM vicidial_auto_calls where uniqueid='$VD_uniqueid[$z]' and server_ip='$server_ip'"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $autocallexists[$z] = "$record->[0]"; + } + } + if ($autocallexists[$z] < 1) + { + $stmtA = "UPDATE vicidial_live_agents set random_id='$VD_random[$z]',status='READY', last_call_finish='$SQLdate',lead_id='',uniqueid='',callerid='',channel='' where user='$VD_user[$z]' and server_ip='$server_ip'"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if ($V) {print STDERR "$VD_user[$z] CALL WIPE UPDATE: $affected_rows|$VD_uniqueid[$z]\n";} + } + + $z++; + } + + + + + + + ############################################################################### + ###### last, wait for a little bit and repeat the loop + ############################################################################### + + ### sleep for X seconds before beginning the loop again + usleep(1*$loop_delay*1000); + + $endless_loop--; + if($DB){print STDERR "\nloop counter: |$endless_loop|\n";} + + ### putting a blank file called "VDAD.kill" in the directory will automatically safely kill this program + if (-e '/home/cron/VDAD.kill') + { + unlink('/home/cron/VDAD.kill'); + $endless_loop=0; + $one_day_interval=0; + print "\nPROCESS KILLED MANUALLY... EXITING\n\n" + } + + $bad_grabber_counter=0; + + + } + + + if($DB){print "DONE... Exiting... Goodbye... See you later... Not really, initiating next loop...\n";} + + $event_string='HANGING UP|'; + &event_logger; + + $one_day_interval--; + +} + + $event_string='CLOSING DB CONNECTION|'; + &event_logger; + + + $dbhA->close; + + + if($DB){print "DONE... Exiting... Goodbye... See you later... Really I mean it this time\n";} + + +exit; + + + + + + + + + + + + + +sub get_time_now #get the current date and time and epoch for logging call lengths and datetimes +{ + $secX = time(); +$secX = time(); + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($secX); + $LOCAL_GMT_OFF = $SERVER_GMT; + $LOCAL_GMT_OFF_STD = $SERVER_GMT; + if ($isdst) {$LOCAL_GMT_OFF++;} + +$GMT_now = ($secX - ($LOCAL_GMT_OFF * 3600)); + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($GMT_now); + if ($hour < 10) {$hour = "0$hour";} + if ($min < 10) {$min = "0$min";} + + if ($DB) {print "TIME DEBUG: $LOCAL_GMT_OFF_STD|$LOCAL_GMT_OFF|$isdst| GMT: $hour:$min\n";} + +($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); +$year = ($year + 1900); +$mon++; +if ($mon < 10) {$mon = "0$mon";} +if ($mday < 10) {$mday = "0$mday";} +if ($hour < 10) {$Fhour = "0$hour";} +if ($min < 10) {$min = "0$min";} +if ($sec < 10) {$sec = "0$sec";} + +$now_date_epoch = time(); +$now_date = "$year-$mon-$mday $hour:$min:$sec"; + $CIDdate = "$mon$mday$hour$min$sec"; + $tsSQLdate = "$year$mon$mday$hour$min$sec"; + $SQLdate = "$year-$mon-$mday $hour:$min:$sec"; + $filedate = "$year-$mon-$mday"; + +$BDtarget = ($secX - 10); +($Bsec,$Bmin,$Bhour,$Bmday,$Bmon,$Byear,$Bwday,$Byday,$Bisdst) = localtime($BDtarget); +$Byear = ($Byear + 1900); +$Bmon++; +if ($Bmon < 10) {$Bmon = "0$Bmon";} +if ($Bmday < 10) {$Bmday = "0$Bmday";} +if ($Bhour < 10) {$Bhour = "0$Bhour";} +if ($Bmin < 10) {$Bmin = "0$Bmin";} +if ($Bsec < 10) {$Bsec = "0$Bsec";} + $BDtsSQLdate = "$Byear$Bmon$Bmday$Bhour$Bmin$Bsec"; + +$PDtarget = ($secX - 30); +($Psec,$Pmin,$Phour,$Pmday,$Pmon,$Pyear,$Pwday,$Pyday,$Pisdst) = localtime($PDtarget); +$Pyear = ($Pyear + 1900); +$Pmon++; +if ($Pmon < 10) {$Pmon = "0$Pmon";} +if ($Pmday < 10) {$Pmday = "0$Pmday";} +if ($Phour < 10) {$Phour = "0$Phour";} +if ($Pmin < 10) {$Pmin = "0$Pmin";} +if ($Psec < 10) {$Psec = "0$Psec";} + $PDtsSQLdate = "$Pyear$Pmon$Pmday$Phour$Pmin$Psec"; + +$XDtarget = ($secX - 120); +($Xsec,$Xmin,$Xhour,$Xmday,$Xmon,$Xyear,$Xwday,$Xyday,$Xisdst) = localtime($XDtarget); +$Xyear = ($Xyear + 1900); +$Xmon++; +if ($Xmon < 10) {$Xmon = "0$Xmon";} +if ($Xmday < 10) {$Xmday = "0$Xmday";} +if ($Xhour < 10) {$Xhour = "0$Xhour";} +if ($Xmin < 10) {$Xmin = "0$Xmin";} +if ($Xsec < 10) {$Xsec = "0$Xsec";} + $XDSQLdate = "$Xyear-$Xmon-$Xmday $Xhour:$Xmin:$Xsec"; + +$TDtarget = ($secX - 600); +($Tsec,$Tmin,$Thour,$Tmday,$Tmon,$Tyear,$Twday,$Tyday,$Tisdst) = localtime($TDtarget); +$Tyear = ($Tyear + 1900); +$Tmon++; +if ($Tmon < 10) {$Tmon = "0$Tmon";} +if ($Tmday < 10) {$Tmday = "0$Tmday";} +if ($Thour < 10) {$Thour = "0$Thour";} +if ($Tmin < 10) {$Tmin = "0$Tmin";} +if ($Tsec < 10) {$Tsec = "0$Tsec";} + $TDSQLdate = "$Tyear-$Tmon-$Tmday $Thour:$Tmin:$Tsec"; + +} + + + + + +sub event_logger +{ + +if ($DB) {print "$now_date|$event_string|\n";} + ### open the log file for writing ### + open(Lout, ">>/home/cron/remote.$filedate") + || die "Can't open /home/cron/remote.$filedate: $!\n"; + + print Lout "$now_date|$event_string|\n"; + + close(Lout); + +$event_string=''; +} diff --git a/AST_agent_week.pl b/AST_agent_week.pl new file mode 100644 index 00000000..e8eb993a --- /dev/null +++ b/AST_agent_week.pl @@ -0,0 +1,336 @@ +#!/usr/bin/perl + +# AST_agent_week.pl +# +# This script is designed to gather stats for all agent activity over the course +# of a week(Sunday to Saturday) and print it in an ASCI text file to be placed +# on a web server for viewing. +# +# CHANGES +# 60517-1100 - First version +# + +$txt = '.txt'; +$US = '_'; +$MT[0] = ''; + +### begin parsing run-time options ### +if (length($ARGV[0])>1) +{ + $i=0; + while ($#ARGV >= $i) + { + $args = "$args $ARGV[$i]"; + $i++; + } + + if ($args =~ /--help/i) + { + print "allowed run time options:\n [-q] = quiet\n [-t] = test\n\n"; + exit; + } + else + { + if ($args =~ /--debug/i) + { + $DB=1; + print "\n-----DEBUG MODE-----\n\n"; + } + if ($args =~ /-q/i) + { + $q=1; $Q=1; + } + if ($args =~ /-t/i) + { + $T=1; $TEST=1; + print "\n-----TESTING-----\n\n"; + } + } +} +else +{ +print "no command line options set\n"; +} +### end parsing run-time options ### + + +$secX = time(); + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); + $year = ($year + 1900); + $mon++; + if ($mon < 10) {$mon = "0$mon";} + if ($mday < 10) {$mday = "0$mday";} + if ($hour < 10) {$hour = "0$hour";} + if ($min < 10) {$min = "0$min";} + if ($sec < 10) {$sec = "0$sec";} + $filedate = "$year$mon$mday-$hour$min$sec"; + $ABIfiledate = "$mon-$mday-$year$us$hour$min$sec"; + $shipdate = "$year-$mon-$mday"; + $datestamp = "$year/$mon/$mday $hour:$min"; + + $STARTtarget = ($secX - (86400 * $wday)); + ($Ssec,$Smin,$Shour,$Smday,$Smon,$Syear,$Swday,$Syday,$Sisdst) = localtime($STARTtarget); + $Syear = ($Syear + 1900); $Smon++; + if ($Smon < 10) {$Smon = "0$Smon";} + if ($Smday < 10) {$Smday = "0$Smday";} + $START_week = (($Syday/7)+1); $START_week = sprintf("%2d", $START_week); + $STARTtarget_date = "$Syear-$Smon-$Smday"; + + $ENDtarget = ($STARTtarget + (86400 * 6)); + ($Ssec,$Smin,$Shour,$Smday,$Smon,$Syear,$Swday,$Syday,$Sisdst) = localtime($ENDtarget); + $Syear = ($Syear + 1900); $Smon++; + if ($Smon < 10) {$Smon = "0$Smon";} + if ($Smday < 10) {$Smday = "0$Smday";} + $ENDtarget_date = "$Syear-$Smon-$Smday"; + + $PAST_STARTtarget = ($STARTtarget - (86400 * 7)); + ($Ssec,$Smin,$Shour,$Smday,$Smon,$Syear,$Swday,$Syday,$Sisdst) = localtime($PAST_STARTtarget); + $Syear = ($Syear + 1900); $Smon++; + if ($Smon < 10) {$Smon = "0$Smon";} + if ($Smday < 10) {$Smday = "0$Smday";} + $PAST_START_week = (($Syday/7)+1); $PAST_START_week = sprintf("%2d", $PAST_START_week); + $PAST_STARTtarget_date = "$Syear-$Smon-$Smday"; + + $PAST_ENDtarget = ($ENDtarget - (86400 * 7)); + ($Ssec,$Smin,$Shour,$Smday,$Smon,$Syear,$Swday,$Syday,$Sisdst) = localtime($PAST_ENDtarget); + $Syear = ($Syear + 1900); $Smon++; + if ($Smon < 10) {$Smon = "0$Smon";} + if ($Smday < 10) {$Smday = "0$Smday";} + $PAST_ENDtarget_date = "$Syear-$Smon-$Smday"; + + $PAST_date[0] = $PAST_STARTtarget_date; + $PAST_day[0] = 'Sunday '; + $PAST_date[6] = $PAST_ENDtarget_date; + $PAST_day[6] = 'Saturday '; + + $PAST_Mondaytarget = ($STARTtarget - (86400 * 6)); + ($Ssec,$Smin,$Shour,$Smday,$Smon,$Syear,$Swday,$Syday,$Sisdst) = localtime($PAST_Mondaytarget); + $Syear = ($Syear + 1900); $Smon++; + if ($Smon < 10) {$Smon = "0$Smon";} + if ($Smday < 10) {$Smday = "0$Smday";} + $PAST_date[1] = "$Syear-$Smon-$Smday"; + $PAST_day[1] = 'Monday '; + + $PAST_Tuesdaytarget = ($STARTtarget - (86400 * 5)); + ($Ssec,$Smin,$Shour,$Smday,$Smon,$Syear,$Swday,$Syday,$Sisdst) = localtime($PAST_Tuesdaytarget); + $Syear = ($Syear + 1900); $Smon++; + if ($Smon < 10) {$Smon = "0$Smon";} + if ($Smday < 10) {$Smday = "0$Smday";} + $PAST_date[2] = "$Syear-$Smon-$Smday"; + $PAST_day[2] = 'Tuesday '; + + $PAST_Wednesdaytarget = ($STARTtarget - (86400 * 4)); + ($Ssec,$Smin,$Shour,$Smday,$Smon,$Syear,$Swday,$Syday,$Sisdst) = localtime($PAST_Wednesdaytarget); + $Syear = ($Syear + 1900); $Smon++; + if ($Smon < 10) {$Smon = "0$Smon";} + if ($Smday < 10) {$Smday = "0$Smday";} + $PAST_date[3] = "$Syear-$Smon-$Smday"; + $PAST_day[3] = 'Wednesday'; + + $PAST_Thursdaytarget = ($STARTtarget - (86400 * 3)); + ($Ssec,$Smin,$Shour,$Smday,$Smon,$Syear,$Swday,$Syday,$Sisdst) = localtime($PAST_Thursdaytarget); + $Syear = ($Syear + 1900); $Smon++; + if ($Smon < 10) {$Smon = "0$Smon";} + if ($Smday < 10) {$Smday = "0$Smday";} + $PAST_date[4] = "$Syear-$Smon-$Smday"; + $PAST_day[4] = 'Thursday '; + + $PAST_Fridaytarget = ($STARTtarget - (86400 * 2)); + ($Ssec,$Smin,$Shour,$Smday,$Smon,$Syear,$Swday,$Syday,$Sisdst) = localtime($PAST_Fridaytarget); + $Syear = ($Syear + 1900); $Smon++; + if ($Smon < 10) {$Smon = "0$Smon";} + if ($Smday < 10) {$Smday = "0$Smday";} + $PAST_date[5] = "$Syear-$Smon-$Smday"; + $PAST_day[5] = 'Friday '; + +print "\n\n\n\n\n\n\n\n\n\n\n\n-- AST_agent_week.pl --\n\n"; +print "This program is designed to print stats to a file for agents' activity for the previous week. \n\n"; + +$TLoutfile = ''; +$TLoutfile .= "TODAY: $shipdate\n"; +$TLoutfile .= "THIS WEEK: week $START_week $STARTtarget_date - $ENDtarget_date\n"; +$TLoutfile .= "LAST WEEK: week $PAST_START_week $PAST_STARTtarget_date - $PAST_ENDtarget_date\n\n"; + +#$h=0; +#foreach(@PAST_date) +#{ +#$TLoutfile .= "$PAST_day[$h] $PAST_date[$h]\n"; +#$h++; +#} + +#print "$TLoutfile"; + + +$outfile = "AGENT_HOURS_$PAST_STARTtarget_date$US$PAST_ENDtarget_date$txt"; + +#$dir = '/usr/local/apache2/htdocs'; +$dir = '/home/www/htdocs'; + +### open the X out file for writing ### +open(out, ">$dir/vicidial/agent_reports/$outfile") + || die "Can't open $outfile: $!\n"; + +### Make sure this file is in a libs path or put the absolute path to it +require("/home/cron/AST_SERVER_conf.pl"); # local configuration file + +if (!$DB_port) {$DB_port='3306';} + +use DBI; + +$dbhA = DBI->connect("DBI:mysql:$DB_database:$DB_server:$DB_port", "$DB_user", "$DB_pass") + or die "Couldn't connect to database: " . DBI->errstr; + +$dbhB = DBI->connect("DBI:mysql:$DB_database:$DB_server:$DB_port", "$DB_user", "$DB_pass") + or die "Couldn't connect to database: " . DBI->errstr; + +#$vicidial_agent_log = 'vicidial_agent_log_archive'; +$vicidial_agent_log = 'vicidial_agent_log'; + +########################################################################### +########### PAST WEEK STAT GATHERING LOOP ################################# +########################################################################### +$h=0; +foreach(@PAST_date) +{ + print out "\n$PAST_day[$h] $PAST_date[$h]\n\n"; + print out "AGENT USER CALLS TALK PAUSE WAIT DISPO ACTIVE LOGTIME FIRST LAST \n"; + print "\n$PAST_day[$h] $PAST_date[$h]\n\n"; + print "AGENT USER CALLS TALK PAUSE WAIT DISPO ACTIVE LOGTIME FIRST LAST \n"; + + $stmtA = "select count(*) as calls, full_name,vicidial_users.user,sum(talk_sec),sum(pause_sec),sum(wait_sec),sum(dispo_sec) from vicidial_users,$vicidial_agent_log where event_time <= '$PAST_date[$h] 23:59:59' and event_time >= '$PAST_date[$h] 00:00:00' and vicidial_users.user=$vicidial_agent_log.user and pause_sec<48800 and wait_sec<48800 and talk_sec<48800 and dispo_sec<48800 group by vicidial_users.user order by full_name limit 10000;"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $rec_count=0; + while ($sthArows > $rec_count) + { + @aryA = $sthA->fetchrow_array; + + $calls = sprintf("%7s", $aryA[0]); + $name = sprintf("%-20s", $aryA[1]); while(length($name)>20) {chop($name);} + $user = sprintf("%-8s", $aryA[2]); + + ### TOTAL ACTIVE TIME + $active = ($aryA[3] + $aryA[4] + $aryA[5] + $aryA[6]); + $TIME_S = $active; + $TIME_H = int($TIME_S / 3600); + $TIME_S = ($TIME_S - ($TIME_H * 3600)); + $TIME_M = int($TIME_S / 60); + $TIME_S = ($TIME_S - ($TIME_M * 60)); + if ($TIME_S < 10) {$TIME_S = "0$TIME_S";} + if ($TIME_M < 10) {$TIME_M = "0$TIME_M";} + $TIME_HMS = "$TIME_H:$TIME_M:$TIME_S"; + $active = sprintf("%9s", $TIME_HMS); + + ### TOTAL TALK TIME + $TIME_S = $aryA[3]; + $TIME_H = int($TIME_S / 3600); + $TIME_S = ($TIME_S - ($TIME_H * 3600)); + $TIME_M = int($TIME_S / 60); + $TIME_S = ($TIME_S - ($TIME_M * 60)); + if ($TIME_S < 10) {$TIME_S = "0$TIME_S";} + if ($TIME_M < 10) {$TIME_M = "0$TIME_M";} + $TIME_HMS = "$TIME_H:$TIME_M:$TIME_S"; + $talk = sprintf("%9s", $TIME_HMS); + + ### TOTAL PAUSE TIME + $TIME_S = $aryA[4]; + $TIME_H = int($TIME_S / 3600); + $TIME_S = ($TIME_S - ($TIME_H * 3600)); + $TIME_M = int($TIME_S / 60); + $TIME_S = ($TIME_S - ($TIME_M * 60)); + if ($TIME_S < 10) {$TIME_S = "0$TIME_S";} + if ($TIME_M < 10) {$TIME_M = "0$TIME_M";} + $TIME_HMS = "$TIME_H:$TIME_M:$TIME_S"; + $pause = sprintf("%9s", $TIME_HMS); + + ### TOTAL WAIT TIME + $TIME_S = $aryA[5]; + $TIME_H = int($TIME_S / 3600); + $TIME_S = ($TIME_S - ($TIME_H * 3600)); + $TIME_M = int($TIME_S / 60); + $TIME_S = ($TIME_S - ($TIME_M * 60)); + if ($TIME_S < 10) {$TIME_S = "0$TIME_S";} + if ($TIME_M < 10) {$TIME_M = "0$TIME_M";} + $TIME_HMS = "$TIME_H:$TIME_M:$TIME_S"; + $wait = sprintf("%9s", $TIME_HMS); + + ### TOTAL DISPO TIME + $TIME_S = $aryA[6]; + $TIME_H = int($TIME_S / 3600); + $TIME_S = ($TIME_S - ($TIME_H * 3600)); + $TIME_M = int($TIME_S / 60); + $TIME_S = ($TIME_S - ($TIME_M * 60)); + if ($TIME_S < 10) {$TIME_S = "0$TIME_S";} + if ($TIME_M < 10) {$TIME_M = "0$TIME_M";} + $TIME_HMS = "$TIME_H:$TIME_M:$TIME_S"; + $dispo = sprintf("%9s", $TIME_HMS); + + $stmtB = "select event_time,UNIX_TIMESTAMP(event_time) from $vicidial_agent_log where event_time <= '$PAST_date[$h] 23:59:59' and event_time >= '$PAST_date[$h] 00:00:00' and user='$aryA[2]' order by event_time limit 1;"; + $sthB = $dbhB->prepare($stmtB) or die "preparing: ",$dbhB->errstr; + $sthB->execute or die "executing: $stmtA ", $dbhB->errstr; + @aryB = $sthB->fetchrow_array; + $first_time = sprintf("%21s", $aryB[0]); + $first_log = $aryB[1]; + + $stmtB = "select event_time,UNIX_TIMESTAMP(event_time) from $vicidial_agent_log where event_time <= '$PAST_date[$h] 23:59:59' and event_time >= '$PAST_date[$h] 00:00:00' and user='$aryA[2]' order by event_time desc limit 1;"; + $sthB = $dbhB->prepare($stmtB) or die "preparing: ",$dbhB->errstr; + $sthB->execute or die "executing: $stmtA ", $dbhB->errstr; + @aryB = $sthB->fetchrow_array; + $last_time = sprintf("%21s", $aryB[0]); + $last_log = $aryB[1]; + + $TIME_S = ($last_log - $first_log); + $TIME_H = int($TIME_S / 3600); + $TIME_S = ($TIME_S - ($TIME_H * 3600)); + $TIME_M = int($TIME_S / 60); + $TIME_S = ($TIME_S - ($TIME_M * 60)); + if ($TIME_S < 10) {$TIME_S = "0$TIME_S";} + if ($TIME_M < 10) {$TIME_M = "0$TIME_M";} + $TIME_HMS = "$TIME_H:$TIME_M:$TIME_S"; + $login_time = sprintf("%9s", $TIME_HMS); + + + + print out "$name$user$calls$talk$pause$wait$dispo$active$login_time$first_time$last_time\n"; + print "$name$user$calls$talk$pause$wait$dispo$active$login_time$first_time$last_time\n"; + + + $rec_count++; + } + $sthA->finish(); + + + + + + + + + + +#if ($h=='1') +# { +# exit; +# } + +$h++; +} + + + +close(out); + +### calculate time to run script ### +$secY = time(); +$secZ = ($secY - $secX); +$secZm = ($secZ /60); + +print "script execution time in seconds: $secZ minutes: $secZm\n"; + +exit; + + + + + diff --git a/AST_cleanup_agent_log.pl b/AST_cleanup_agent_log.pl new file mode 100644 index 00000000..7f405a09 --- /dev/null +++ b/AST_cleanup_agent_log.pl @@ -0,0 +1,236 @@ +#!/usr/bin/perl +# +# AST_cleanup_agent_log.pl version 0.1 +# +# DESCRIPTION: +# to be run frequently to clean up the vicidial_agent_log to fix erroneous time +# calculations due to out-of-order vicidial_agent_log updates. This happens 0.5% +# of the time in our test setups, but that leads to inaccurate time logs so we +# wrote this script to fix the miscalculations +# +# This program only needs to be run by one server +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# + + +# constants +$COUNTER_OUTPUT=1; # set to 1 to display the counter as the script runs +$US='__'; +$MT[0]=''; + +### begin parsing run-time options ### +if (length($ARGV[0])>1) +{ + $i=0; + while ($#ARGV >= $i) + { + $args = "$args $ARGV[$i]"; + $i++; + } + + if ($args =~ /--help/i) + { + print "allowed run time options:\n [-t] = test\n [-debug] = verbose debug messages\n[-debugX] = Extra-verbose debug messages\n\n"; + } + else + { + if ($args =~ /-debug/i) + { + $DB=1; # Debug flag + print "\n----- DEBUGGING -----\n\n"; + } + if ($args =~ /--debugX/i) + { + $DBX=1; + print "\n----- SUPER-DUPER DEBUGGING -----\n\n"; + } + if ($args =~ /-t/i) + { + $TEST=1; + $T=1; + print "\n----- TEST RUN, NO UPDATES -----\n\n"; + } + } +} +else +{ +# print "no command line options set\n"; +} +### end parsing run-time options ### + +### Make sure this file is in a libs path or put the absolute path to it +require("/home/cron/AST_SERVER_conf.pl"); # local configuration file + +if (!$DB_port) {$DB_port='3306';} + +use Net::MySQL; + + my $dbhA = Net::MySQL->new(hostname => "$DB_server", database => "$DB_database", user => "$DB_user", password => "$DB_pass", port => "$DB_port") + or die "Couldn't connect to database: $DB_server - $DB_database\n"; + + + + if ($DB) {print " - cleaning up pause time\n";} + ### Grab any pause time record greater than 50000 + $stmtA = "SELECT agent_log_id,pause_epoch,wait_epoch from vicidial_agent_log where pause_sec>50000;"; + if ($DBX) {print "$stmtA\n";} + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $i=0; + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $DBout = ''; + $agent_log_id[$i] = "$record->[0]"; + $pause_epoch[$i] = "$record->[1]"; + $wait_epoch[$i] = "$record->[2]"; + $pause_sec[$i] = int($wait_epoch[$i] - $pause_epoch[$i]); + if ( ($pause_sec[$i] < 0) || ($pause_sec[$i] > 50000) ) + { + $DBout = "Override output: $pause_sec[$i]"; + $pause_sec[$i] = 0; + } + if ($DBX) {print "$i - $agent_log_id[$i] |$wait_epoch[$i]|$pause_epoch[$i]|$pause_sec[$i]|$DBout|\n";} + $i++; + } + } + $h=0; + while ($h < $i) + { + $stmtA = "UPDATE vicidial_agent_log set pause_sec='$pause_sec[$h]' where agent_log_id='$agent_log_id[$h]';"; + if($DBX){print STDERR "\n|$stmtA|\n";} + if (!$TEST) {$dbhA->query($stmtA); }# or die "Couldn't execute query: |$stmtA|\n"; + $h++; + } + if ($DB) {print STDERR " Pause times fixed: $h\n";} + + + + + + @agent_log_id=@MT; + @wait_epoch=@MT; + + if ($DBX) {print "\n\n";} + if ($DB) {print " - cleaning up wait time\n";} + ### Grab any pause time record greater than 50000 + $stmtA = "SELECT agent_log_id,wait_epoch,talk_epoch from vicidial_agent_log where wait_sec>50000;"; + if ($DBX) {print "$stmtA\n";} + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $i=0; + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $DBout = ''; + $agent_log_id[$i] = "$record->[0]"; + $wait_epoch[$i] = "$record->[1]"; + $talk_epoch[$i] = "$record->[2]"; + $wait_sec[$i] = int($talk_epoch[$i] - $wait_epoch[$i]); + if ( ($wait_sec[$i] < 0) || ($wait_sec[$i] > 50000) ) + { + $DBout = "Override output: $wait_sec[$i]"; + $wait_sec[$i] = 0; + } + if ($DBX) {print "$i - $agent_log_id[$i] |$talk_epoch[$i]|$wait_epoch[$i]|$wait_sec[$i]|$DBout|\n";} + $i++; + } + } + $h=0; + while ($h < $i) + { + $stmtA = "UPDATE vicidial_agent_log set wait_sec='$wait_sec[$h]' where agent_log_id='$agent_log_id[$h]';"; + if($DBX){print STDERR "\n|$stmtA|\n";} + if (!$TEST) {$dbhA->query($stmtA); }# or die "Couldn't execute query: |$stmtA|\n"; + $h++; + } + if ($DB) {print STDERR " Wait times fixed: $h\n";} + + + + + + @agent_log_id=@MT; + @talk_epoch=@MT; + + if ($DBX) {print "\n\n";} + if ($DB) {print " - cleaning up talk time\n";} + ### Grab any pause time record greater than 50000 + $stmtA = "SELECT agent_log_id,talk_epoch,dispo_epoch from vicidial_agent_log where talk_sec>50000;"; + if ($DBX) {print "$stmtA\n";} + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $i=0; + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $DBout = ''; + $agent_log_id[$i] = "$record->[0]"; + $talk_epoch[$i] = "$record->[1]"; + $dispo_epoch[$i] = "$record->[2]"; + $talk_sec[$i] = int($dispo_epoch[$i] - $talk_epoch[$i]); + if ( ($talk_sec[$i] < 0) || ($talk_sec[$i] > 50000) ) + { + $DBout = "Override output: $talk_sec[$i]"; + $talk_sec[$i] = 0; + } + if ($DBX) {print "$i - $agent_log_id[$i] |$dispo_epoch[$i]|$talk_epoch[$i]|$talk_sec[$i]|$DBout|\n";} + $i++; + } + } + $h=0; + while ($h < $i) + { + $stmtA = "UPDATE vicidial_agent_log set talk_sec='$talk_sec[$h]' where agent_log_id='$agent_log_id[$h]';"; + if($DBX){print STDERR "|$stmtA|\n";} + if (!$TEST) {$dbhA->query($stmtA); }# or die "Couldn't execute query: |$stmtA|\n"; + $h++; + } + if ($DB) {print STDERR " Talk times fixed: $h\n";} + + + + + + @agent_log_id=@MT; + @dispo_epoch=@MT; + + if ($DBX) {print "\n\n";} + if ($DB) {print " - cleaning up dispo time\n";} + $stmtA = "UPDATE vicidial_agent_log set dispo_sec='0' where dispo_sec>50000;"; + if($DBX){print STDERR "|$stmtA|\n";} + if (!$TEST) + { + $dbhA->query($stmtA); # or die "Couldn't execute query: |$stmtA|\n"; + $affected_rows = $dbhA->get_affected_rows_length; + } + if ($DB) {print STDERR " Bad Dispo times zeroed out: $affected_rows\n";} + + + + + + + + + + + + if ($DB) {print STDERR "\nDONE\n";} + + + + $dbhA->close; + + +exit; + + + + + + diff --git a/AST_conf_update.pl b/AST_conf_update.pl new file mode 100644 index 00000000..70d874a9 --- /dev/null +++ b/AST_conf_update.pl @@ -0,0 +1,220 @@ +#!/usr/bin/perl +# +# AST_conf_update.pl version 0.3 +# +# DESCRIPTION: +# uses the Asterisk Manager interface and Net::MySQL to update whether a conference +# is still in use or not. If not in use 3 times in a row the extension in the +# conferences DB record is erased freeing that conference to be used again +# +# SUMMARY: +# This program was designed for people using the Asterisk PBX with conferences +# +# This program should be in the cron running every minute (like AST_vm_update.pl) +# +# For this program to work you need to have the "asterisk" MySQL database +# created with the conferences table in it, also make sure +# that the account running this program has read/write/update/delete access +# to that database +# +# It is recommended that you run this program on the local Asterisk machine +# +# If this script is run ever minute there is a theoretical limit of +# 600 conferences that it can check due to the wait interval. If you have +# more than this either change the cron when this script is run or change the +# wait interval below +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# +# 50810-1532 - Added database server variable definitions lookup +# 50823-1456 - Added commandline arguments for debug at runtime +# + +# constants +$DB=0; # Debug flag, set to 0 for no debug messages per minute +$US='__'; +$MT[0]=''; + +### begin parsing run-time options ### +if (length($ARGV[0])>1) +{ + $i=0; + while ($#ARGV >= $i) + { + $args = "$args $ARGV[$i]"; + $i++; + } + + if ($args =~ /--help/i) + { + print "allowed run time options:\n [-t] = test\n [-debug] = verbose debug messages\n\n"; + } + else + { + if ($args =~ /-debug/i) + { + $DB=1; # Debug flag + } + if ($args =~ /-t/i) + { + $TEST=1; + $T=1; + } + } +} +else +{ +# print "no command line options set\n"; +} +### end parsing run-time options ### + +### Make sure this file is in a libs path or put the absolute path to it +require("/home/cron/AST_SERVER_conf.pl"); # local configuration file + +if (!$DB_port) {$DB_port='3306';} + +use lib './lib', '../lib'; +use Time::HiRes ('gettimeofday','usleep','sleep'); # necessary to have perl sleep command of less than one second +use Net::MySQL; +use Net::Telnet (); + + + my $dbhA = Net::MySQL->new(hostname => "$DB_server", database => "$DB_database", user => "$DB_user", password => "$DB_pass", port => "$DB_port") + or die "Couldn't connect to database: $DB_server - $DB_database\n"; + +### Grab Server values from the database +$stmtA = "SELECT telnet_host,telnet_port,ASTmgrUSERNAME,ASTmgrSECRET,ASTmgrUSERNAMEupdate,ASTmgrUSERNAMElisten,ASTmgrUSERNAMEsend,max_vicidial_trunks,answer_transfer_agent,local_gmt,ext_context FROM servers where server_ip = '$server_ip';"; +$dbhA->query("$stmtA"); +if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $DBtelnet_host = "$record->[0]"; + $DBtelnet_port = "$record->[1]"; + $DBASTmgrUSERNAME = "$record->[2]"; + $DBASTmgrSECRET = "$record->[3]"; + $DBASTmgrUSERNAMEupdate = "$record->[4]"; + $DBASTmgrUSERNAMElisten = "$record->[5]"; + $DBASTmgrUSERNAMEsend = "$record->[6]"; + $DBmax_vicidial_trunks = "$record->[7]"; + $DBanswer_transfer_agent= "$record->[8]"; + $DBSERVER_GMT = "$record->[9]"; + $DBext_context = "$record->[10]"; + if ($DBtelnet_host) {$telnet_host = $DBtelnet_host;} + if ($DBtelnet_port) {$telnet_port = $DBtelnet_port;} + if ($DBASTmgrUSERNAME) {$ASTmgrUSERNAME = $DBASTmgrUSERNAME;} + if ($DBASTmgrSECRET) {$ASTmgrSECRET = $DBASTmgrSECRET;} + if ($DBASTmgrUSERNAMEupdate) {$ASTmgrUSERNAMEupdate = $DBASTmgrUSERNAMEupdate;} + if ($DBASTmgrUSERNAMElisten) {$ASTmgrUSERNAMElisten = $DBASTmgrUSERNAMElisten;} + if ($DBASTmgrUSERNAMEsend) {$ASTmgrUSERNAMEsend = $DBASTmgrUSERNAMEsend;} + if ($DBmax_vicidial_trunks) {$max_vicidial_trunks = $DBmax_vicidial_trunks;} + if ($DBanswer_transfer_agent) {$answer_transfer_agent = $DBanswer_transfer_agent;} + if ($DBSERVER_GMT) {$SERVER_GMT = $DBSERVER_GMT;} + if ($DBext_context) {$ext_context = $DBext_context;} + } + } + + + +@PTextensions=@MT; @PT_conf_extens=@MT; @PTmessages=@MT; @PTold_messages=@MT; @NEW_messages=@MT; @OLD_messages=@MT; +$dbhA->query("SELECT extension,conf_exten from conferences where server_ip='$server_ip' and extension is NOT NULL and extension != '';"); +if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_count=0; + while ( $record = $iter->each) + { + $PTextensions[$rec_count] = "$record->[0]"; + $PT_conf_extens[$rec_count] = "$record->[1]"; + $rec_count++; + } + } + +if (!$telnet_port) {$telnet_port = '5038';} + +### connect to asterisk manager through telnet +$t = new Net::Telnet (Port => $telnet_port, + Prompt => '/.*[\$%#>] $/', + Output_record_separator => '',); +#$fh = $t->dump_log("$telnetlog"); # uncomment for telnet log + if (length($ASTmgrUSERNAMEsend) > 3) {$telnet_login = $ASTmgrUSERNAMEsend;} + else {$telnet_login = $ASTmgrUSERNAME;} + +$t->open("$telnet_host"); +$t->waitfor('/0\n$/'); # print login +$t->print("Action: Login\nUsername: $telnet_login\nSecret: $ASTmgrSECRET\n\n"); +$t->waitfor('/Authentication accepted/'); # waitfor auth accepted + + +$i=0; +foreach(@PTextensions) + { + @list_channels=@MT; + $t->buffer_empty; + @list_channels = $t->cmd(String => "Action: Command\nCommand: Meetme list $PT_conf_extens[$i]\n\nAction: Ping\n\n", Prompt => '/Response: Pong.*/'); + + $j=0; + $conf_empty[$i]=0; + $conf_users[$i]=''; + foreach(@list_channels) + { + if($DB){print "|$list_channels[$j]|\n";} + if ($list_channels[$j] =~ /No active conferences|No such conference/i) + {$conf_empty[$i]++;} +# if ($list_channels[$j] =~ /^User /i) +# { +# $userx = ''; +# $userx = $list_channels[$j]; +# $userx =~ s/User \#: //gi; +# $conf_users[$i] .= "$userx|"; +# } + $j++; + } + + if($DB){print "Meetme list $PT_conf_extens[$i]- Exten:|$PTextensions[$i]| Empty:|$conf_empty[$i]| ";} + if (!$conf_empty[$i]) + { + if($DB){print "CONFERENCE STILL HAS PARTICIPANTS, DOING NOTHING FOR THIS CONFERENCE\n";} + if ($PTextensions[$i] =~ /Xtimeout\d$/i) + { + $PTextensions[$i] =~ s/Xtimeout\d$//gi; + $stmtA = "UPDATE conferences set extension='$PTextensions[$i]' where server_ip='$server_ip' and conf_exten='$PT_conf_extens[$i]';"; + if($DB){print STDERR "\n|$stmtA|\n";} + $dbhA->query($stmtA) or die "Couldn't execute query:|$stmtA|\n"; + } + } + else + { + $NEWexten[$i] = $PTextensions[$i]; + if ($PTextensions[$i] =~ /Xtimeout3$/i) {$NEWexten[$i] =~ s/Xtimeout3$/Xtimeout2/gi;} + if ($PTextensions[$i] =~ /Xtimeout2$/i) {$NEWexten[$i] =~ s/Xtimeout2$/Xtimeout1/gi;} + if ($PTextensions[$i] =~ /Xtimeout1$/i) {$NEWexten[$i] = '';} + if ( ($PTextensions[$i] !~ /Xtimeout\d$/i) and (length($PTextensions[$i])> 0) ) {$NEWexten[$i] .= 'Xtimeout3';} + + + $stmtA = "UPDATE conferences set extension='$NEWexten[$i]' where server_ip='$server_ip' and conf_exten='$PT_conf_extens[$i]';"; + if($DB){print STDERR "\n|$stmtA|\n";} + $dbhA->query($stmtA) or die "Couldn't execute query:|$stmtA|\n"; + } + + $i++; + ### sleep for 10 hundredths of a second + usleep(1*100*1000); + } + + +$t->buffer_empty; +@hangup = $t->cmd(String => "Action: Logoff\n\n", Prompt => "/.*/"); +$t->buffer_empty; +$ok = $t->close; + +$dbhA->close; + +if($DB){print "DONE... Exiting... Goodbye... See you later... \n";} + +exit; + + + + diff --git a/AST_flush_DBqueue.pl b/AST_flush_DBqueue.pl new file mode 100644 index 00000000..cf76ffa7 --- /dev/null +++ b/AST_flush_DBqueue.pl @@ -0,0 +1,189 @@ +#!/usr/bin/perl +# +# AST_flush_DBqueue.pl version 0.2 +# +# DESCRIPTION: +# - clears out mysql records for this server for the ACQS vicidial_manager table +# - optimizes tables used frequently by VICIDIAL +# +# It is recommended that you run this program on the local Asterisk machine +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# + +$secX = time(); + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); + $year = ($year + 1900); + $yy = $year; $yy =~ s/^..//gi; + $mon++; + if ($mon < 10) {$mon = "0$mon";} + if ($mday < 10) {$mday = "0$mday";} + if ($hour < 10) {$hour = "0$hour";} + if ($min < 10) {$min = "0$min";} + if ($sec < 10) {$sec = "0$sec";} +$SQLdate_NOW="$year-$mon-$mday $hour:$min:$sec"; + +($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time()-3600); + $year = ($year + 1900); + $yy = $year; $yy =~ s/^..//gi; + $mon++; + if ($mon < 10) {$mon = "0$mon";} + if ($mday < 10) {$mday = "0$mday";} + if ($hour < 10) {$hour = "0$hour";} + if ($min < 10) {$min = "0$min";} + if ($sec < 10) {$sec = "0$sec";} +$SQLdate_NEG_1hour="$year-$mon-$mday $hour:$min:$sec"; + +### begin parsing run-time options ### +if (length($ARGV[0])>1) +{ + $i=0; + while ($#ARGV >= $i) + { + $args = "$args $ARGV[$i]"; + $i++; + } + + if ($args =~ /--help/i) + { + print "allowed run time options:\n [-q] = quiet\n [-t] = test\n [--debug] = debugging messages\n\n"; + } + else + { + if ($args =~ /-q/i) + { + $q=1; $Q=1; + } + if ($args =~ /--debug/i) + { + $DB=1; + print "\n-----DEBUGGING -----\n\n"; + } + if ($args =~ /-t|--test/i) + { + $T=1; $TEST=1; + print "\n-----TESTING -----\n\n"; + } + } +} +else +{ +print "no command line options set\n"; +} +### end parsing run-time options ### + + +if (!$Q) {print "TEST\n\n";} +if (!$Q) {print "NOW DATETIME: $SQLdate_NOW\n";} +if (!$Q) {print "1 HOUR AGO DATETIME: $SQLdate_NEG_1hour\n\n";} + +### Make sure this file is in a libs path or put the absolute path to it +require("/home/cron/AST_SERVER_conf.pl"); # local configuration file + +if (!$DB_port) {$DB_port='3306';} + +use Net::MySQL; + + my $dbhA = Net::MySQL->new(hostname => "$DB_server", database => "$DB_database", user => "$DB_user", password => "$DB_pass", port => "$DB_port") + or die "Couldn't connect to database: $DB_server - $DB_database\n"; + + + + $stmtA = "delete from vicidial_manager where server_ip='$server_ip' and entry_date < '$SQLdate_NEG_1hour';"; + if($DB){print STDERR "\n|$stmtA|\n";} + if (!$T) {$dbhA->query($stmtA); } + if (!$Q) {print " - vicidial_manager 2 hour flush\n";} + + + $stmtA = "update park_log set status='HUNGUP' where hangup_time is not null;"; + if($DB){print STDERR "\n|$stmtA|\n";} + if (!$T) {$dbhA->query($stmtA); } + if ($dbhA->has_selected_record) + { + $iterA=$dbhA->create_record_iterator; + $rec_countY=0; + while ($recordA = $iterA->each) + { + if (!$Q) {print "|",$recordA->[0],"|",$recordA->[1],"|",$recordA->[2],"|",$recordA->[3],"|","\n";} + } + } + + if (!$Q) {print " - park_log HUNGUP flush \n";} + + + $stmtA = "optimize table vicidial_manager;"; + if($DB){print STDERR "\n|$stmtA|\n";} + if (!$T) {$dbhA->query($stmtA); } + if ($dbhA->has_selected_record) + { + $iterA=$dbhA->create_record_iterator; + $rec_countY=0; + while ($recordA = $iterA->each) + { + if (!$Q) {print "|",$recordA->[0],"|",$recordA->[1],"|",$recordA->[2],"|",$recordA->[3],"|","\n";} + } + } + + if (!$Q) {print " - optimize vicidial_manager \n";} + + + $stmtA = "optimize table vicidial_live_agents;"; + if($DB){print STDERR "\n|$stmtA|\n";} + if (!$T) {$dbhA->query($stmtA); } + if ($dbhA->has_selected_record) + { + $iterA=$dbhA->create_record_iterator; + $rec_countY=0; + while ($recordA = $iterA->each) + { + if (!$Q) {print "|",$recordA->[0],"|",$recordA->[1],"|",$recordA->[2],"|",$recordA->[3],"|","\n";} + } + } + + if (!$Q) {print " - optimize vicidial_live_agents \n";} + + + $stmtA = "optimize table vicidial_auto_calls;"; + if($DB){print STDERR "\n|$stmtA|\n";} + if (!$T) {$dbhA->query($stmtA); } + if ($dbhA->has_selected_record) + { + $iterA=$dbhA->create_record_iterator; + $rec_countY=0; + while ($recordA = $iterA->each) + { + if (!$Q) {print "|",$recordA->[0],"|",$recordA->[1],"|",$recordA->[2],"|",$recordA->[3],"|","\n";} + } + } + + if (!$Q) {print " - optimize vicidial_auto_calls \n";} + + + $stmtA = "optimize table vicidial_hopper;"; + if($DB){print STDERR "\n|$stmtA|\n";} + if (!$T) {$dbhA->query($stmtA); } + if ($dbhA->has_selected_record) + { + $iterA=$dbhA->create_record_iterator; + $rec_countY=0; + while ($recordA = $iterA->each) + { + if (!$Q) {print "|",$recordA->[0],"|",$recordA->[1],"|",$recordA->[2],"|",$recordA->[3],"|","\n";} + } + } + + if (!$Q) {print " - optimize vicidial_hopper \n";} + + + + + $dbhA->close; + + +exit; + + + + + + diff --git a/AST_manager_kill_hung_congested.pl b/AST_manager_kill_hung_congested.pl new file mode 100644 index 00000000..52636af4 --- /dev/null +++ b/AST_manager_kill_hung_congested.pl @@ -0,0 +1,335 @@ +#!/usr/bin/perl +# +# AST_manager_kill_hung_congested.pl version 0.2 +# +# Part of the Asterisk Central Queue System (ACQS) +# +# DESCRIPTION: +# kills CONGEST local channels every 15 seconds +# +# For the client program to work in ACQS mode, this program must be running +# +# For this program to work you need to have the "asterisk" MySQL database +# created and create the tables listed in the CONF_MySQL.txt file, also make sure +# that the machine running this program has read/write/update/delete access +# to that database +# +# In your Asterisk server setup you also need to have several things activated +# and defined. See the CONF_Asterisk.txt file for details +# +# put this in the cron to run every minute +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# +# 50823-1525 - Added commandline debug options with debug printouts +# + +# constants +$DB=0; # Debug flag, set to 0 for no debug messages, On an active system this will generate thousands of lines of output per minute +$US='__'; +$MT[0]=''; + + +### begin parsing run-time options ### +if (length($ARGV[0])>1) +{ + $i=0; + while ($#ARGV >= $i) + { + $args = "$args $ARGV[$i]"; + $i++; + } + + if ($args =~ /--help/i) + { + print "allowed run time options:\n [-t] = test\n [-debug] = verbose debug messages\n[-debugX] = Extra-verbose debug messages\n\n"; + } + else + { + if ($args =~ /-debug/i) + { + $DB=1; # Debug flag + } + if ($args =~ /--debugX/i) + { + $DBX=1; + print "\n----- SUPER-DUPER DEBUGGING -----\n\n"; + } + if ($args =~ /-t/i) + { + $TEST=1; + $T=1; + } + } +} +else +{ +# print "no command line options set\n"; +} +### end parsing run-time options ### + + +### Make sure this file is in a libs path or put the absolute path to it +require("/home/cron/AST_SERVER_conf.pl"); # local configuration file + + + &get_time_now; + +# $event_string='PROGRAM STARTED||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||'; +# &event_logger; + +#use lib './lib', '../lib'; +use Net::MySQL; +#use Net::Telnet (); + +my $dbhA = Net::MySQL->new(hostname => "$DB_server", database => "$DB_database", user => "$DB_user", password => "$DB_pass") +or die "Couldn't connect to database: \n"; + +#$event_string='LOGGED INTO MYSQL SERVER ON 1 CONNECTION|'; +#&event_logger; + +$stmtA = "SELECT channel FROM live_sip_channels where server_ip = '$server_ip' and extension = 'CONGEST' and channel LIKE \"Local%\" limit 99"; +# $event_string="SQL_QUERY|$stmtA|"; +# &event_logger; + +$dbhA->query("$stmtA"); +if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_count=0; + while ( $record = $iter->each) + { + if($DB){print STDERR $record->[0],"\n";} + $congest_kill[$rec_count] = "$record->[0]"; + $rec_count++; + } + + } + +$i=0; +foreach(@congest_kill) + { + $i_count = $i; + if ($i_count < 10) {$i_count = "0$i_count";} + + if (length($congest_kill[$i])>0) + { + ### use manager middleware-app to zapbarge call being placed from meetme + $KCqueryCID = "KC$i_count$CIDdate"; + + ### insert a NEW record to the vicidial_manager table to be processed + $stmtA = "INSERT INTO vicidial_manager values('','','$now_date','NEW','N','$server_ip','','Hangup','$KCqueryCID','Channel: $congest_kill[$i]','','','','','','','','','')"; + + $event_string = "SUBRT|killing_congest|KC|$KCqueryCID|$congest_kill[$i]|$stmtA|"; + event_logger; + + if ($DB) {print "KILLING $congest_kill[$i]\n";} + $dbhA->query($stmtA) or die "Couldn't execute query:\n"; + } + $i++; + } + + +sleep(14); + +######## 22222 starting another loop + &get_time_now; +@congest_kill = @MT; + + + +$stmtA = "SELECT channel FROM live_sip_channels where server_ip = '$server_ip' and extension = 'CONGEST' and channel LIKE \"Local%\" limit 99"; +# $event_string="SQL_QUERY|$stmtA|"; +# &event_logger; + +$dbhA->query("$stmtA"); +if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_count=0; + while ( $record = $iter->each) + { + if($DB){print STDERR $record->[0],"\n";} + $congest_kill[$rec_count] = "$record->[0]"; + $rec_count++; + } + + } + +$i=0; +foreach(@congest_kill) + { + $i_count = $i; + if ($i_count < 10) {$i_count = "0$i_count";} + + if (length($congest_kill[$i])>0) + { + ### use manager middleware-app to zapbarge call being placed from meetme + $KCqueryCID = "KC$i_count$CIDdate"; + + ### insert a NEW record to the vicidial_manager table to be processed + $stmtA = "INSERT INTO vicidial_manager values('','','$now_date','NEW','N','$server_ip','','Hangup','$KCqueryCID','Channel: $congest_kill[$i]','','','','','','','','','')"; + + $event_string = "SUBRT|killing_congest|KC|$KCqueryCID|$congest_kill[$i]|$stmtA|"; + event_logger; + + if ($DB) {print "KILLING $congest_kill[$i]\n";} + $dbhA->query($stmtA) or die "Couldn't execute query:\n"; + } + $i++; + } + + +sleep(15); + +######## 33333 starting another loop + &get_time_now; +@congest_kill = @MT; + + + + +$stmtA = "SELECT channel FROM live_sip_channels where server_ip = '$server_ip' and extension = 'CONGEST' and channel LIKE \"Local%\" limit 99"; +# $event_string="SQL_QUERY|$stmtA|"; +# &event_logger; + +$dbhA->query("$stmtA"); +if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_count=0; + while ( $record = $iter->each) + { + if($DB){print STDERR $record->[0],"\n";} + $congest_kill[$rec_count] = "$record->[0]"; + $rec_count++; + } + + } + +$i=0; +foreach(@congest_kill) + { + $i_count = $i; + if ($i_count < 10) {$i_count = "0$i_count";} + + if (length($congest_kill[$i])>0) + { + ### use manager middleware-app to zapbarge call being placed from meetme + $KCqueryCID = "KC$i_count$CIDdate"; + + ### insert a NEW record to the vicidial_manager table to be processed + $stmtA = "INSERT INTO vicidial_manager values('','','$now_date','NEW','N','$server_ip','','Hangup','$KCqueryCID','Channel: $congest_kill[$i]','','','','','','','','','')"; + + $event_string = "SUBRT|killing_congest|KC|$KCqueryCID|$congest_kill[$i]|$stmtA|"; + event_logger; + + if ($DB) {print "KILLING $congest_kill[$i]\n";} + $dbhA->query($stmtA) or die "Couldn't execute query:\n"; + } + $i++; + } + + +sleep(15); + +######## 44444 starting another loop + &get_time_now; +@congest_kill = @MT; + + + + + +$stmtA = "SELECT channel FROM live_sip_channels where server_ip = '$server_ip' and extension = 'CONGEST' and channel LIKE \"Local%\" limit 99"; +# $event_string="SQL_QUERY|$stmtA|"; +# &event_logger; + +$dbhA->query("$stmtA"); +if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_count=0; + while ( $record = $iter->each) + { + if($DB){print STDERR $record->[0],"\n";} + $congest_kill[$rec_count] = "$record->[0]"; + $rec_count++; + } + + } + +$i=0; +foreach(@congest_kill) + { + $i_count = $i; + if ($i_count < 10) {$i_count = "0$i_count";} + + if (length($congest_kill[$i])>0) + { + ### use manager middleware-app to zapbarge call being placed from meetme + $KCqueryCID = "KC$i_count$CIDdate"; + + ### insert a NEW record to the vicidial_manager table to be processed + $stmtA = "INSERT INTO vicidial_manager values('','','$now_date','NEW','N','$server_ip','','Hangup','$KCqueryCID','Channel: $congest_kill[$i]','','','','','','','','','')"; + + $event_string = "SUBRT|killing_congest|KC|$KCqueryCID|$congest_kill[$i]|$stmtA|"; + event_logger; + + if ($DB) {print "KILLING $congest_kill[$i]\n";} + $dbhA->query($stmtA) or die "Couldn't execute query:\n"; + } + $i++; + } + + + +# $event_string='CLOSING DB CONNECTION|'; +# &event_logger; + + $dbhA->close; + + + if($DB){print "DONE... Exiting... Goodbye... See you later... \n";} + + +exit; + + + + + + + +sub get_time_now #get the current date and time and epoch for logging call lengths and datetimes +{ +($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); +$year = ($year + 1900); +$mon++; +if ($mon < 10) {$mon = "0$mon";} +if ($mday < 10) {$mday = "0$mday";} +if ($hour < 10) {$Fhour = "0$hour";} +if ($min < 10) {$min = "0$min";} +if ($sec < 10) {$sec = "0$sec";} + +$now_date_epoch = time(); +$now_date = "$year-$mon-$mday $hour:$min:$sec"; +$action_log_date = "$year-$mon-$mday"; +$CIDdate = "$year$mon$mday$hour$min$sec"; +} + + + + + +sub event_logger { + ### open the log file for writing ### + open(Lout, ">>$KHLOGfile") + || die "Can't open $KHLOGfile: $!\n"; + + print Lout "$now_date|$event_string|\n"; + + close(Lout); + +$event_string=''; +} diff --git a/AST_manager_listen.pl b/AST_manager_listen.pl new file mode 100644 index 00000000..6d407cbd --- /dev/null +++ b/AST_manager_listen.pl @@ -0,0 +1,594 @@ +#!/usr/bin/perl +# +# AST_manager_listen.pl version 1.1.11 build 60403-1230 +# +# Part of the Asterisk Central Queue System (ACQS) +# +# DESCRIPTION: +# connects to the Asterisk Manager interface and updates records in the +# vicidial_manager table of the asterisk database in MySQL based upon the +# events that it receives +# +# SUMMARY: +# This program was designed as the listen-only part of the ACQS. It's job is to +# look for certain events and based upon either the uniqueid or the callerid of +# the call update the status and information of an action record in the +# vicidial_manager table of the asterisk MySQL database. +# +# Win32 - ActiveState Perl 5.8.0 +# UNIX - Gnome or KDE with Tk/Tcl and perl Tk/Tcl modules loaded +# Both - Net::MySQL, Net::Telnet and Time::HiRes perl modules loaded +# +# For the client program to work in ACQS mode, this program must be running +# +# For this program to work you need to have the "asterisk" MySQL database +# created and create the tables listed in the CONF_MySQL.txt file, also make sure +# that the machine running this program has read/write/update/delete access +# to that database +# +# In your Asterisk server setup you also need to have several things activated +# and defined. See the CONF_Asterisk.txt file for details +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# +# changes: +# 50322-1300 changed callerid parsing to remove quotes and number +# 50616-1559 Added NewCallerID parsing and updating +# 50621-1406 Added Asterisk server shutdown and connection dead detection +# 50810-1534 Added database server variable definitions lookup +# 50824-1606 Altered CVS/1.2 support for different output +# 50901-2359 Another CVS/1.2 output parsing fix +# 51222-1553 fixed parentheses bug in manager output +# 60403-1230 Added SVN/1.2.6 support for different output +# + +# constants +$DB=1; # Debug flag, set to 0 for no debug messages, lots of output +$US='__'; +$MT[0]=''; + +### begin parsing run-time options ### +if (length($ARGV[0])>1) +{ + $i=0; + while ($#ARGV >= $i) + { + $args = "$args $ARGV[$i]"; + $i++; + } + + if ($args =~ /--help/i) + { + print "allowed run time options:\n [-t] = test\n [-debug] = verbose debug messages\n[-debugX] = Extra-verbose debug messages\n\n"; + } + else + { + if ($args =~ /-debug/i) + { + $DB=1; # Debug flag + } + if ($args =~ /--debugX/i) + { + $DBX=1; + print "\n----- SUPER-DUPER DEBUGGING -----\n\n"; + } + if ($args =~ /-t/i) + { + $TEST=1; + $T=1; + } + } +} +else +{ +# print "no command line options set\n"; +} +### end parsing run-time options ### + + + +### Make sure this file is in a libs path or put the absolute path to it +require("/home/cron/AST_SERVER_conf.pl"); # local configuration file + +if (!$DB_port) {$DB_port='3306';} + + &get_time_now; + + $event_string='PROGRAM STARTED||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||'; + &event_logger; + +#use lib './lib', '../lib'; +use Time::HiRes ('gettimeofday','usleep','sleep'); # necessary to have perl sleep command of less than one second +use Net::MySQL; +use Net::Telnet (); + + my $dbhA = Net::MySQL->new(hostname => "$DB_server", database => "$DB_database", user => "$DB_user", password => "$DB_pass", port => "$DB_port") + or die "Couldn't connect to database: $DB_server - $DB_database\n"; + + $event_string='LOGGED INTO MYSQL SERVER ON 1 CONNECTION|'; + &event_logger; + + +### Grab Server values from the database +$stmtA = "SELECT telnet_host,telnet_port,ASTmgrUSERNAME,ASTmgrSECRET,ASTmgrUSERNAMEupdate,ASTmgrUSERNAMElisten,ASTmgrUSERNAMEsend,max_vicidial_trunks,answer_transfer_agent,local_gmt,ext_context FROM servers where server_ip = '$server_ip';"; +$dbhA->query("$stmtA"); +if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $DBtelnet_host = "$record->[0]"; + $DBtelnet_port = "$record->[1]"; + $DBASTmgrUSERNAME = "$record->[2]"; + $DBASTmgrSECRET = "$record->[3]"; + $DBASTmgrUSERNAMEupdate = "$record->[4]"; + $DBASTmgrUSERNAMElisten = "$record->[5]"; + $DBASTmgrUSERNAMEsend = "$record->[6]"; + $DBmax_vicidial_trunks = "$record->[7]"; + $DBanswer_transfer_agent= "$record->[8]"; + $DBSERVER_GMT = "$record->[9]"; + $DBext_context = "$record->[10]"; + if ($DBtelnet_host) {$telnet_host = $DBtelnet_host;} + if ($DBtelnet_port) {$telnet_port = $DBtelnet_port;} + if ($DBASTmgrUSERNAME) {$ASTmgrUSERNAME = $DBASTmgrUSERNAME;} + if ($DBASTmgrSECRET) {$ASTmgrSECRET = $DBASTmgrSECRET;} + if ($DBASTmgrUSERNAMEupdate) {$ASTmgrUSERNAMEupdate = $DBASTmgrUSERNAMEupdate;} + if ($DBASTmgrUSERNAMElisten) {$ASTmgrUSERNAMElisten = $DBASTmgrUSERNAMElisten;} + if ($DBASTmgrUSERNAMEsend) {$ASTmgrUSERNAMEsend = $DBASTmgrUSERNAMEsend;} + if ($DBmax_vicidial_trunks) {$max_vicidial_trunks = $DBmax_vicidial_trunks;} + if ($DBanswer_transfer_agent) {$answer_transfer_agent = $DBanswer_transfer_agent;} + if ($DBSERVER_GMT) {$SERVER_GMT = $DBSERVER_GMT;} + if ($DBext_context) {$ext_context = $DBext_context;} + } + } + + +if (!$telnet_port) {$telnet_port = '5038';} + +$one_day_interval = 90; # 1 day loops for 3 months +while($one_day_interval > 0) +{ + + $event_string="STARTING NEW MANAGER TELNET CONNECTION||ATTEMPT|ONE DAY INTERVAL:$one_day_interval|"; + &event_logger; +# Errmode => Return, + + ### connect to asterisk manager through telnet + $tn = new Net::Telnet (Port => $telnet_port, + Prompt => '/.*[\$%#>] $/', + Output_record_separator => '',); + #$fh = $tn->dump_log("$LItelnetlog"); # uncomment for telnet log + if (length($ASTmgrUSERNAMElisten) > 3) {$telnet_login = $ASTmgrUSERNAMElisten;} + else {$telnet_login = $ASTmgrUSERNAME;} + $tn->open("$telnet_host"); + $tn->waitfor('/0\n$/'); # print login + $tn->print("Action: Login\nUsername: $telnet_login\nSecret: $ASTmgrSECRET\n\n"); + $tn->waitfor('/Authentication accepted/'); # waitfor auth accepted + + $tn->buffer_empty; + + $event_string="STARTING NEW MANAGER TELNET CONNECTION|$telnet_login|CONFIRMED CONNECTION|ONE DAY INTERVAL:$one_day_interval|"; + &event_logger; + + $endless_loop=864000; # 1 day at .10 seconds per loop + + while($endless_loop > 0) + { + ### sleep for 10 hundredths of a second + usleep(1*100*1000); + + $msg=''; + $read_input_buf = $tn->get(Errmode => Return, Timeout => 1,); + $input_buf_length = length($read_input_buf); + $msg = $tn->errmsg; + if ($msg =~ /filehandle isn\'t open/i) + { + $endless_loop=0; + $one_day_interval=0; + print "ERRMSG: |$msg|\n"; + print "\nAsterisk server shutting down, PROCESS KILLED... EXITING\n\n"; + $event_string="Asterisk server shutting down, PROCESS KILLED... EXITING|ONE DAY INTERVAL:$one_day_interval|$msg|"; + &event_logger; + } + + if ( ($read_input_buf !~ /\n\n/) or ($input_buf_length < 10) ) + { + # if ($read_input_buf =~ /\n/) {print "\n|||$input_buf_length|||$read_input_buf|||\n";} + $input_buf = "$input_buf$read_input_buf"; + } + else + { + $partial=0; + $partial_input_buf=''; + + if ($read_input_buf !~ /\n\n$/) + { + $read_input_buf =~ s/\(|\)/ /gi; # replace parens with space + $partial_input_buf = $read_input_buf; + $partial_input_buf =~ s/\n/-----/gi; + $partial_input_buf =~ s/\*/\\\*/gi; + $partial_input_buf =~ s/.*----------//gi; + $partial_input_buf =~ s/-----/\n/gi; + $read_input_buf =~ s/$partial_input_buf$//gi; + $partial++; + } + + +# |1 DIALINGs updated| +# Nested quantifiers in regex; marked by <-- HERE in m/Event: Newexten +# Channel: Zap/16-1 +# Context: demo +# Extension: 990009*CL_UMGCOF_L** <-- HERE 1479503*conf*** +# Priority: 2 +# Application: Dial +# AppData: Zap/g3/90009*CL_UMGCOF_L**1479503*conf***|20 +# Uniqueid: 1101224775.6783 +# $/ at /home/cron/AST_manager_listen.pl line 114. + + + $input_buf = "$input_buf$read_input_buf"; + @input_lines = split(/\n\n/, $input_buf); + + if($DB){print "input buffer: $input_buf_length lines: $#input_lines partial: $partial\n";} + if ( ($DB) && ($partial) ) {print "-----[$partial_input_buf]-----\n\n";} + if($DB){print "|$input_buf|\n";} + + $manager_string = "$input_buf"; + &manager_output_logger; + + $input_buf = "$partial_input_buf"; + + + @command_line=@MT; + $ILcount=0; + foreach(@input_lines) + { + if ( ($input_lines[$ILcount] =~ /State: Ringing|State: Up|State: Dialing|Event: Newstate|Event: Hangup|Event: Newcallerid|Event: Shutdown/) && ($input_lines[$ILcount] !~ /ZOMBIE/) ) + { + $input_lines[$ILcount] =~ s/^\n|^\n\n//gi; + @command_line=split(/\n/, $input_lines[$ILcount]); + if ($input_lines[$ILcount] =~ /Event: Shutdown/) + { + $endless_loop=0; + $one_day_interval=0; + print "\nAsterisk server shutting down, PROCESS KILLED... EXITING\n\n"; + $event_string="Asterisk server shutting down, PROCESS KILLED... EXITING|ONE DAY INTERVAL:$one_day_interval|"; + &event_logger; + } + + if ($input_lines[$ILcount] =~ /Event: Hangup/) + { + if ( ($command_line[2] =~ /^Channel: /i) && ($command_line[3] =~ /^Uniqueid: /i) ) ### post 2005-08-07 CVS -- added Privilege line + { + $channel = $command_line[2]; + $channel =~ s/Channel: |\s*$//gi; + $uniqueid = $command_line[3]; + $uniqueid =~ s/Uniqueid: |\s*$//gi; + $stmtA = "UPDATE vicidial_manager set status='DEAD', channel='$channel' where server_ip = '$server_ip' and uniqueid = '$uniqueid'"; + + print STDERR "|$stmtA|\n"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if($DB){print "|$affected_rows HANGUPS updated|\n";} + } + else + { + if ( ($command_line[3] =~ /^Channel: /i) && ($command_line[4] =~ /^Uniqueid: /i) ) ### post 2006-03-20 SVN -- Added Timestamp line + { + $channel = $command_line[3]; + $channel =~ s/Channel: |\s*$//gi; + $uniqueid = $command_line[4]; + $uniqueid =~ s/Uniqueid: |\s*$//gi; + $stmtA = "UPDATE vicidial_manager set status='DEAD', channel='$channel' where server_ip = '$server_ip' and uniqueid = '$uniqueid'"; + + print STDERR "|$stmtA|\n"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if($DB){print "|$affected_rows HANGUPS updated|\n";} + } + else + { + $channel = $command_line[1]; + $channel =~ s/Channel: |\s*$//gi; + $uniqueid = $command_line[2]; + $uniqueid =~ s/Uniqueid: |\s*$//gi; + $stmtA = "UPDATE vicidial_manager set status='DEAD', channel='$channel' where server_ip = '$server_ip' and uniqueid = '$uniqueid'"; + + print STDERR "|$stmtA|\n"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if($DB){print "|$affected_rows HANGUPS updated|\n";} + } + } + } + + if ($input_lines[$ILcount] =~ /State: Dialing/) + { + if ( ($command_line[1] =~ /^Channel: /i) && ($command_line[4] =~ /^Uniqueid: /i) ) ### pre 2004-10-07 CVS + { + $channel = $command_line[1]; + $channel =~ s/Channel: |\s*$//gi; + $callid = $command_line[3]; + $callid =~ s/Callerid: |\s*$//gi; + $callid =~ s/^\"//gi; $callid =~ s/\".*$//gi; + $uniqueid = $command_line[4]; + $uniqueid =~ s/Uniqueid: |\s*$//gi; + $stmtA = "UPDATE vicidial_manager set status='SENT', channel='$channel', uniqueid = '$uniqueid' where server_ip = '$server_ip' and callerid = '$callid'"; + print STDERR "|$stmtA|\n"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if($DB){print "|$affected_rows DIALINGs updated|\n";} + } + if ( ($command_line[1] =~ /^Channel: /i) && ($command_line[4] =~ /^CalleridName: /i) ) ### post 2004-10-07 CVS + { + $channel = $command_line[1]; + $channel =~ s/Channel: |\s*$//gi; + $callid = $command_line[4]; + $callid =~ s/CalleridName: |\s*$//gi; + $callid =~ s/^\"//gi; $callid =~ s/\".*$//gi; + $uniqueid = $command_line[5]; + $uniqueid =~ s/Uniqueid: |\s*$//gi; + $stmtA = "UPDATE vicidial_manager set status='SENT', channel='$channel', uniqueid = '$uniqueid' where server_ip = '$server_ip' and callerid = '$callid'"; + print STDERR "|$stmtA|\n"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if($DB){print "|$affected_rows DIALINGs updated|\n";} + } + if ( ($command_line[2] =~ /^Channel: /i) && ($command_line[5] =~ /^CalleridName: /i) ) ### post 2005-08-07 CVS + { + $channel = $command_line[2]; + $channel =~ s/Channel: |\s*$//gi; + $callid = $command_line[5]; + $callid =~ s/CalleridName: |\s*$//gi; + $callid =~ s/^\"//gi; $callid =~ s/\".*$//gi; + $uniqueid = $command_line[6]; + $uniqueid =~ s/Uniqueid: |\s*$//gi; + $stmtA = "UPDATE vicidial_manager set status='SENT', channel='$channel', uniqueid = '$uniqueid' where server_ip = '$server_ip' and callerid = '$callid'"; + print STDERR "|$stmtA|\n"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if($DB){print "|$affected_rows DIALINGs updated|\n";} + } + if ( ($command_line[3] =~ /^Channel: /i) && ($command_line[6] =~ /^CalleridName: /i) ) ### post 2006-03-20 -- Added Timestamp line + { + $channel = $command_line[3]; + $channel =~ s/Channel: |\s*$//gi; + $callid = $command_line[6]; + $callid =~ s/CalleridName: |\s*$//gi; + $callid =~ s/^\"//gi; $callid =~ s/\".*$//gi; + $uniqueid = $command_line[7]; + $uniqueid =~ s/Uniqueid: |\s*$//gi; + $stmtA = "UPDATE vicidial_manager set status='SENT', channel='$channel', uniqueid = '$uniqueid' where server_ip = '$server_ip' and callerid = '$callid'"; + print STDERR "|$stmtA|\n"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if($DB){print "|$affected_rows DIALINGs updated|\n";} + } + } + if ($input_lines[$ILcount] =~ /State: Ringing|State: Up/) + { + if ( ($command_line[1] =~ /^Channel: /i) && ($command_line[4] =~ /^Uniqueid: /i) ) ### pre 2004-10-07 CVS + { + $channel = $command_line[1]; + $channel =~ s/Channel: |\s*$//gi; + $callid = $command_line[3]; + $callid =~ s/Callerid: |\s*$//gi; + $callid =~ s/^\"//gi; $callid =~ s/\".*$//gi; + $uniqueid = $command_line[4]; + $uniqueid =~ s/Uniqueid: |\s*$//gi; + $stmtA = "UPDATE vicidial_manager set status='UPDATED', channel='$channel', uniqueid = '$uniqueid' where server_ip = '$server_ip' and callerid = '$callid'"; + if ($channel !~ /local/i) + { + print STDERR "|$stmtA|\n"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if($DB){print "|$affected_rows RINGINGs updated|\n";} + } + } + if ( ($command_line[1] =~ /^Channel: /i) && ($command_line[4] =~ /^CalleridName: /i) ) ### post 2004-10-07 CVS + { + $channel = $command_line[1]; + $channel =~ s/Channel: |\s*$//gi; + $callid = $command_line[4]; + $callid =~ s/CalleridName: |\s*$//gi; + $callid =~ s/^\"//gi; $callid =~ s/\".*$//gi; + $uniqueid = $command_line[5]; + $uniqueid =~ s/Uniqueid: |\s*$//gi; + $stmtA = "UPDATE vicidial_manager set status='UPDATED', channel='$channel', uniqueid = '$uniqueid' where server_ip = '$server_ip' and callerid = '$callid'"; + if ($channel !~ /local/i) + { + print STDERR "|$stmtA|\n"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if($DB){print "|$affected_rows RINGINGs updated|\n";} + } + } + if ( ($command_line[2] =~ /^Channel: /i) && ($command_line[5] =~ /^CalleridName: /i) ) ### post 2005-08-07 CVS + { + $channel = $command_line[2]; + $channel =~ s/Channel: |\s*$//gi; + $callid = $command_line[5]; + $callid =~ s/CalleridName: |\s*$//gi; + $callid =~ s/^\"//gi; $callid =~ s/\".*$//gi; + $uniqueid = $command_line[6]; + $uniqueid =~ s/Uniqueid: |\s*$//gi; + $stmtA = "UPDATE vicidial_manager set status='UPDATED', channel='$channel', uniqueid = '$uniqueid' where server_ip = '$server_ip' and callerid = '$callid'"; + if ($channel !~ /local/i) + { + print STDERR "|$stmtA|\n"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if($DB){print "|$affected_rows RINGINGs updated|\n";} + } + } + if ( ($command_line[3] =~ /^Channel: /i) && ($command_line[6] =~ /^CalleridName: /i) ) ### post 2006-03-20 SVN -- Added Timestamp line + { + $channel = $command_line[3]; + $channel =~ s/Channel: |\s*$//gi; + $callid = $command_line[6]; + $callid =~ s/CalleridName: |\s*$//gi; + $callid =~ s/^\"//gi; $callid =~ s/\".*$//gi; + $uniqueid = $command_line[7]; + $uniqueid =~ s/Uniqueid: |\s*$//gi; + $stmtA = "UPDATE vicidial_manager set status='UPDATED', channel='$channel', uniqueid = '$uniqueid' where server_ip = '$server_ip' and callerid = '$callid'"; + if ($channel !~ /local/i) + { + print STDERR "|$stmtA|\n"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if($DB){print "|$affected_rows RINGINGs updated|\n";} + } + } + } + + if ($input_lines[$ILcount] =~ /Event: Newcallerid/) + { + if ( ($command_line[1] =~ /^Channel: /i) && ($command_line[3] =~ /^Uniqueid: /i) ) + { + $channel = $command_line[1]; + $channel =~ s/Channel: |\s*$//gi; + $callid = $command_line[2]; + $callid =~ s/Callerid: |\s*$//gi; + $callid =~ s/^\"//gi; $callid =~ s/\".*$//gi; + $uniqueid = $command_line[3]; + $uniqueid =~ s/Uniqueid: |\s*$//gi; + $stmtA = "UPDATE vicidial_manager set status='UPDATED', channel='$channel', uniqueid = '$uniqueid' where server_ip = '$server_ip' and callerid = '$callid'"; + if ($channel =~ /local/i) + { + print STDERR "|$stmtA|\n"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if($DB){print "|$affected_rows RINGINGs updated|\n";} + } + } + if ( ($command_line[3] =~ /^Channel: /i) && ($command_line[6] =~ /^Uniqueid: /i) ) ### post 2006-03-20 SVN -- Added Timestamp line + { + $channel = $command_line[3]; + $channel =~ s/Channel: |\s*$//gi; + $callid = $command_line[5]; + $callid =~ s/Callerid: |\s*$//gi; + $callid =~ s/^\"//gi; $callid =~ s/\".*$//gi; + $uniqueid = $command_line[6]; + $uniqueid =~ s/Uniqueid: |\s*$//gi; + $stmtA = "UPDATE vicidial_manager set status='UPDATED', channel='$channel', uniqueid = '$uniqueid' where server_ip = '$server_ip' and callerid = '$callid'"; + if ($channel =~ /local/i) + { + print STDERR "|$stmtA|\n"; + $dbhA->query("$stmtA"); + my $affected_rows = $dbhA->get_affected_rows_length; + if($DB){print "|$affected_rows RINGINGs updated|\n";} + } + } + } + + } + $ILcount++; + } + + } + + + $endless_loop--; + $keepalive_count_loop++; + if($DB){print STDERR "loop counter: |$endless_loop|$keepalive_count_loop|\r";} + + ### putting a blank file called "sendmgr.kill" in a directory will automatically safely kill this program + if ( (-e '/home/cron/listenmgr.kill') or ($sendonlyone) ) + { + unlink('/home/cron/listenmgr.kill'); + $endless_loop=0; + $one_day_interval=0; + print "\nPROCESS KILLED MANUALLY... EXITING\n\n"; + } + + ### run a keepalive command to flush whatever is in the buffer through and to keep the connection alive + if ($endless_loop =~ /00$|50$/) + { + &get_time_now; + + @list_lines = $tn->cmd(String => "Action: Command\nCommand: show uptime\n\n", Prompt => '/--END COMMAND--.*/', Errmode => Return, Timeout => 1); + if($DB){print "input lines: $#list_lines\n";} + + if($DB){print "+++++++++++++++++++++++++++++++sending keepalive transmit line $endless_loop|$now_date|\n";} + $keepalive_count_loop=0; + } + + + } + + + if($DB){print "DONE... Exiting... Goodbye... See you later... Not really, initiating next loop...$one_day_interval left\n";} + + $event_string='HANGING UP|'; + &event_logger; + + @hangup = $tn->cmd(String => "Action: Logoff\n\n", Prompt => "/.*/", Errmode => Return, Timeout => 1); + + $ok = $tn->close; + + $one_day_interval--; + +} + + $event_string='CLOSING DB CONNECTION|'; + &event_logger; + + + $dbhA->close; + + + if($DB){print "DONE... Exiting... Goodbye... See you later... Really I mean it this time\n";} + + +exit; + + + + + + + +sub get_time_now #get the current date and time and epoch for logging call lengths and datetimes +{ +($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); +$year = ($year + 1900); +$mon++; +if ($mon < 10) {$mon = "0$mon";} +if ($mday < 10) {$mday = "0$mday";} +if ($hour < 10) {$Fhour = "0$hour";} +if ($min < 10) {$min = "0$min";} +if ($sec < 10) {$sec = "0$sec";} + +$now_date_epoch = time(); +$now_date = "$year-$mon-$mday $hour:$min:$sec"; +$action_log_date = "$year-$mon-$mday"; +} + + + + + +sub event_logger { + ### open the log file for writing ### + open(Lout, ">>$LILOGfile") + || die "Can't open $LILOGfile: $!\n"; + + print Lout "$now_date|$event_string|\n"; + + close(Lout); + +$event_string=''; +} + + + + +sub manager_output_logger +{ +open(MOout, ">>/home/cron/listen.$action_log_date") + || die "Can't open /home/cron/listen.$action_log_date: $!\n"; + + print MOout "$now_date|$manager_string|\n"; + + close(MOout); +} diff --git a/AST_manager_send.pl b/AST_manager_send.pl new file mode 100644 index 00000000..222b6a9e --- /dev/null +++ b/AST_manager_send.pl @@ -0,0 +1,384 @@ +#!/usr/bin/perl +# +# AST_manager_send.pl version 0.2 +# +# Part of the Asterisk Central Queue System (ACQS) +# +# DESCRIPTION: +# spawns child processes (AST_send_action_child.pl) to execute action commands +# on the Asterisk manager interface from records in the vicidial_manager table +# of the asterisk database in MySQL that are marked as a status of NEW +# +# SUMMARY: +# This program was designed as the send-only part of the ACQS. It's job is to +# pick NEW actions from the vicidial_manager table and send them to be executed +# by separate child process. This allows for a higher degree of flexibility and +# scalability over just using a single process. Also, this means that a single +# action execution lock cannot bring the entire system down. +# +# Win32 - ActiveState Perl 5.8.0 +# UNIX - Gnome or KDE with Tk/Tcl and perl Tk/Tcl modules loaded +# Both - Net::MySQL, Net::Telnet and Time::HiRes perl modules loaded +# +# For the client program to work in ACQS mode, this program must be running +# +# For this program to work you need to have the "asterisk" MySQL database +# created and create the tables listed in the CONF_MySQL.txt file, also make sure +# that the machine running this program has read/write/update/delete access +# to that database +# +# In your Asterisk server setup you also need to have several things activated +# and defined. See the CONF_Asterisk.txt file for details +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# +# 50823-1514 - Added commandline debug options with debug printouts +# 50902-1051 - Added extra debug output launch sub(commented out) +# + +# constants +$COUNTER_OUTPUT=1; # set to 1 to display the counter as the script runs +$US='__'; +$MT[0]=''; + +### begin parsing run-time options ### +if (length($ARGV[0])>1) +{ + $i=0; + while ($#ARGV >= $i) + { + $args = "$args $ARGV[$i]"; + $i++; + } + + if ($args =~ /--help/i) + { + print "allowed run time options:\n [-t] = test\n [-debug] = verbose debug messages\n[-debugX] = Extra-verbose debug messages\n\n"; + } + else + { + if ($args =~ /-debug/i) + { + $DB=1; # Debug flag + } + if ($args =~ /--debugX/i) + { + $DBX=1; + print "\n----- SUPER-DUPER DEBUGGING -----\n\n"; + } + if ($args =~ /-sendonlyone/i) + { + $sendonlyone=1; + print "\n-----SEND ONLY ONE COMMAND -----\n\n"; + } + if ($args =~ /-t/i) + { + $TEST=1; + $T=1; + } + } +} +else +{ +# print "no command line options set\n"; +} +### end parsing run-time options ### + +### Make sure this file is in a libs path or put the absolute path to it +require("/home/cron/AST_SERVER_conf.pl"); # local configuration file + +if (!$DB_port) {$DB_port='3306';} + + &get_time_now; + + $event_string='PROGRAM STARTED||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||'; + &event_logger; + +#use lib './lib', '../lib'; +use Time::HiRes ('gettimeofday','usleep','sleep'); # necessary to have perl sleep command of less than one second +use Net::MySQL; +#use Net::Telnet (); + + my $dbhA = Net::MySQL->new(hostname => "$DB_server", database => "$DB_database", user => "$DB_user", password => "$DB_pass", port => "$DB_port") + or die "Couldn't connect to database: $DB_server - $DB_database\n"; + + + $event_string='LOGGED INTO MYSQL SERVER ON 1 CONNECTION|'; + &event_logger; + +$one_day_interval = 90; # 1 day loops for 3 months +while($one_day_interval > 0) +{ + + + $endless_loop=864000; # 10 days at .20 seconds per loop + + while($endless_loop > 0) + { + + $affected_rows=0; + $NEW_actions=0; + + $stmtA = "SELECT count(*) from vicidial_manager where server_ip = '$server_ip' and status = 'NEW'"; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_count=0; + while ( $record = $iter->each) + { + if($DB){print STDERR $record->[0]," NEW Actions to send on server $server_ip $endless_loop\n";} + $NEW_actions = "$record->[0]"; + } + } + + if (!$NEW_actions) + { + $affected_rows=0; + } + else + { + $stmtA = "UPDATE vicidial_manager set status='QUEUE' where server_ip = '$server_ip' and status = 'NEW' order by entry_date limit 1"; + $dbhA->query("$stmtA"); + $affected_rows = $dbhA->get_affected_rows_length; + if ($DB) {print STDERR "rows updated to QUEUE: |$affected_rows|\n";} + } + + + if ($affected_rows) + { + $stmtA = "SELECT * FROM vicidial_manager where server_ip = '$server_ip' and status = 'QUEUE' order by entry_date desc limit 1"; + $event_string="SQL_QUERY|$stmtA|"; + &event_logger; + + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_count=0; + while ( $record = $iter->each) + { + if($DB){print STDERR $record->[0],"|", $record->[1],"|", $record->[6],"|", $record->[7],"|", $record->[8],"\n";} + $man_id = "$record->[0]"; + $uniqueid = "$record->[1]"; + $channel = "$record->[6]"; + $action = "$record->[7]"; + $callid = "$record->[8]"; + $cmd_line_b = "$record->[9]"; + $cmd_line_c = "$record->[10]"; + $cmd_line_d = "$record->[11]"; + $cmd_line_e = "$record->[12]"; + $cmd_line_f = "$record->[13]"; + $cmd_line_g = "$record->[14]"; + $cmd_line_h = "$record->[15]"; + $cmd_line_i = "$record->[16]"; + $cmd_line_j = "$record->[17]"; + $cmd_line_k = "$record->[18]"; + + $originate_command = ''; + $originate_command .= "Action: $action\n"; + if (length($cmd_line_b)>3) {$originate_command .= "$cmd_line_b\n";} + if (length($cmd_line_c)>3) {$originate_command .= "$cmd_line_c\n";} + if (length($cmd_line_d)>3) {$originate_command .= "$cmd_line_d\n";} + if (length($cmd_line_e)>3) {$originate_command .= "$cmd_line_e\n";} + if (length($cmd_line_f)>3) {$originate_command .= "$cmd_line_f\n";} + if (length($cmd_line_g)>3) {$originate_command .= "$cmd_line_g\n";} + if (length($cmd_line_h)>3) {$originate_command .= "$cmd_line_h\n";} + if (length($cmd_line_i)>3) {$originate_command .= "$cmd_line_i\n";} + if (length($cmd_line_j)>3) {$originate_command .= "$cmd_line_j\n";} + if (length($cmd_line_k)>3) {$originate_command .= "$cmd_line_k\n";} + $originate_command .= "\n"; + + $SENDNOW=1; + if ($originate_command =~ /Action: Hangup|Action: Redirect/) + { + $SENDNOW=0; + if($DB){print STDERR "\n|checking for dead call before executing|$callid|$uniqueid|\n";} + $dbhA->query("SELECT count(*) FROM vicidial_manager where server_ip = '$server_ip' and callerid='$callid' and status = 'DEAD'"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_countH=0; + while ( $record = $iter->each) + { + $rec_countH = "$record->[0]"; + } + if (!$rec_countH){$SENDNOW=1;} + else + { + $launch_string = "|not sending command line is dead|$callid|$uniqueid|"; + # &launch_logger; + if($DB){print STDERR "\n$launch_string\n";} + + } + } + + } + + $event_string="----BEGIN NEW COMMAND----\n$originate_command----END NEW COMMAND----\n"; + &event_logger; + + if ($SENDNOW) + { + # $tn->buffer_empty; + + $launch_string = "/home/cron/AST_send_action_child.pl --data1=$man_id $callid $uniqueid $channel"; + # &launch_logger; + + system("/home/cron/AST_send_action_child.pl --data1=$man_id >> /home/cron/action.$action_log_date \&"); + + $launch_string = "SENT $man_id $callid $uniqueid $channel"; + # &launch_logger; + + $stmtA = "UPDATE vicidial_manager set status='SENT' where man_id='$man_id'"; + if($DB){print STDERR "\n|$stmtA|\n";} + $dbhA->query($stmtA); + + $event_string="SQL_QUERY|$stmtA|"; + &event_logger; + } + else + { + $stmtA = "UPDATE vicidial_manager set status='DEAD' where man_id='$man_id'"; + if($DB){print STDERR "\n|$stmtA|\n";} + $dbhA->query($stmtA); + $event_string="COMMAND NOT SENT, SQL_QUERY|$stmtA|"; + &event_logger; + } + + } + } + + } + + if ($affected_rows) + { + ### sleep for 10 hundredths of a second + usleep(1*100*1000); + } + else + { + ### sleep for 20 hundredths of a second + usleep(1*200*1000); + } + + $endless_loop--; + if( ($COUNTER_OUTPUT) or ($DB) ){print STDERR "loop counter: |$endless_loop|\r";} + + ### putting a blank file called "sendmgr.kill" in a directory will automatically safely kill this program + if ( (-e '/home/cron/sendmgr.kill') or ($sendonlyone) ) + { + unlink('/home/cron/sendmgr.kill'); + $endless_loop=0; + $one_day_interval=0; + print "\nPROCESS KILLED MANUALLY... EXITING\n\n"; + } + + if ($endless_loop =~ /0$/) + { + &get_time_now; + + if( ($COUNTER_OUTPUT) or ($DB) ){print "checking to see if listener is dead |$sendonlyone|$running_listen|\n";} + #@psoutput = `/bin/ps -f --no-headers -A`; + @psoutput = `/bin/ps -o "%p %a" --no-headers -A`; + + $running_listen = 0; + + $i=0; + foreach (@psoutput) + { + chomp($psoutput[$i]); + + if ($DBX) {print "$i|$psoutput[$i]| \n";} + @psline = split(/\/usr\/bin\/perl /,$psoutput[$i]); + + if ($psline[1] =~ /AST_manager_li/) + { + $running_listen++; + if ($DB) {print "SEND RUNNING: |$psline[1]|\n";} + } + + $i++; + } + + if (!$running_listen) + { + $sendonlyone++; + if( ($COUNTER_OUTPUT) or ($DB) ){print "LISTENER DEAD STOPPING PROGRAM... ATTEMPTING TO START keepalive SCRIPT\n";} + $event_string='LISTENER DEAD STOPPING PROGRAM... ATTEMPTING TO START keepalive SCRIPT|'; + &event_logger; + `/usr/bin/at now < /home/cron/ADMIN_keepalive_send_listen.at 2>/dev/null 1>&2`; + } + } + + + } + + + if( ($COUNTER_OUTPUT) or ($DB) ){print "DONE... Exiting... Goodbye... See you later... Not really, initiating next loop...$one_day_interval left\n";} + + $one_day_interval--; + +} + + $event_string='CLOSING DB CONNECTION|'; + &event_logger; + + + $dbhA->close; + + + if( ($COUNTER_OUTPUT) or ($DB) ){print "DONE... Exiting... Goodbye... See you later... Really I mean it this time\n";} + + +exit; + + + + + + + +sub get_time_now #get the current date and time and epoch for logging call lengths and datetimes +{ +($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); +$year = ($year + 1900); +$mon++; +if ($mon < 10) {$mon = "0$mon";} +if ($mday < 10) {$mday = "0$mday";} +if ($hour < 10) {$Fhour = "0$hour";} +if ($min < 10) {$min = "0$min";} +if ($sec < 10) {$sec = "0$sec";} + +$now_date_epoch = time(); +$now_date = "$year-$mon-$mday $hour:$min:$sec"; +$action_log_date = "$year-$mon-$mday"; +} + + + + + +sub event_logger { + ### open the log file for writing ### + open(Lout, ">>$MSLOGfile") + || die "Can't open $MSLOGfile: $!\n"; + + print Lout "$now_date|$event_string|\n"; + + close(Lout); + +$event_string=''; +} + +sub launch_logger { + ### open the log file for writing ### + open(LLout, ">>/home/cron/action_launch.$action_log_date") + || die "Can't open /home/cron/action_launch.$action_log_date: $!\n"; + + print LLout "$now_date|$launch_string|\n"; + + close(LLout); + +$event_string=''; +} diff --git a/AST_reset_mysql_vars.pl b/AST_reset_mysql_vars.pl new file mode 100644 index 00000000..0409266a --- /dev/null +++ b/AST_reset_mysql_vars.pl @@ -0,0 +1,72 @@ +#!/usr/bin/perl +# +# AST_reset_mysql_vars.pl version 0.2 +# +# !!! DO NOT RUN THIS WHILE THERE ARE ACTIVE CALLS ON THE ASTERISK SERVER !!! +# +# DESCRIPTION: +# clears out mysql records for this server +# +# It is recommended that you run this program on the local Asterisk machine +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# + + +### Make sure this file is in a libs path or put the absolute path to it +require("/home/cron/AST_SERVER_conf.pl"); # local configuration file + +if (!$DB_port) {$DB_port='3306';} + +use Net::MySQL; + + my $dbhA = Net::MySQL->new(hostname => "$DB_server", database => "$DB_database", user => "$DB_user", password => "$DB_pass", port => "$DB_port") + or die "Couldn't connect to database: $DB_server - $DB_database\n"; + + + + $stmtA = "UPDATE conferences set extension='' where server_ip='$server_ip';"; + if($DB){print STDERR "\n|$stmtA|\n";} + $dbhA->query($stmtA); # or die "Couldn't execute query: |$stmtA|\n"; + print " - conferences reset\n"; + + $stmtA = "UPDATE vicidial_conferences set extension='' where server_ip='$server_ip';"; + if($DB){print STDERR "\n|$stmtA|\n";} + $dbhA->query($stmtA); # or die "Couldn't execute query: |$stmtA|\n"; + print " - vicidial_conferences reset\n"; + +# $stmtA = "UPDATE vicidial_manager set status='DEAD' where server_ip='$server_ip' and status='NEW';"; +# if($DB){print STDERR "\n|$stmtA|\n";} +# $dbhA->query($stmtA); # or die "Couldn't execute query: |$stmtA|\n"; +# print " - vicidial_manager queue reset\n"; + + $stmtA = "DELETE from vicidial_manager where server_ip='$server_ip';"; + if($DB){print STDERR "\n|$stmtA|\n";} + $dbhA->query($stmtA); # or die "Couldn't execute query: |$stmtA|\n"; + print " - vicidial_manager delete\n"; + + $stmtA = "DELETE from vicidial_auto_calls where server_ip='$server_ip';"; + if($DB){print STDERR "\n|$stmtA|\n";} + $dbhA->query($stmtA); # or die "Couldn't execute query: |$stmtA|\n"; + print " - vicidial_manager delete\n"; + + $stmtA = "DELETE from vicidial_live_agents where server_ip='$server_ip';"; + if($DB){print STDERR "\n|$stmtA|\n";} + $dbhA->query($stmtA); # or die "Couldn't execute query: |$stmtA|\n"; + print " - vicidial_manager delete\n"; + + $stmtA = "DELETE from vicidial_users where full_name='5555';"; + if($DB){print STDERR "\n|$stmtA|\n";} + $dbhA->query($stmtA); # or die "Couldn't execute query: |$stmtA|\n"; + print " - vicidial_manager delete\n"; + + $dbhA->close; + + +exit; + + + + + + diff --git a/AST_send_action_child.pl b/AST_send_action_child.pl new file mode 100644 index 00000000..b15eb8b8 --- /dev/null +++ b/AST_send_action_child.pl @@ -0,0 +1,258 @@ +#!/usr/bin/perl +# +# AST_send_action_child.pl version 0.2 +# +# Part of the Asterisk Central Queue System (ACQS) +# +# DESCRIPTION: +# This script is spawned every time an action is to be executed by the main +# AST_manager_send.pl script and sends actions blindly to the Asterisk manager +# +# SUMMARY: +# This program was designed as the blind-send part of the ACQS. It's job is to +# be spawned by the AST_manager_send.pl script lookup the record in the MySQL DB +# to be executed. connect to the manager interface, send the action and logoff +# then exit. +# +# Win32 - ActiveState Perl 5.8.0 +# UNIX - Gnome or KDE with Tk/Tcl and perl Tk/Tcl modules loaded +# Both - Net::MySQL, Net::Telnet and Time::HiRes perl modules loaded +# +# For the client program to work in ACQS mode, this program must be running +# +# For this program to work you need to have the "asterisk" MySQL database +# created and create the tables listed in the CONF_MySQL.txt file, also make sure +# that the machine running this program has read/write/update/delete access +# to that database +# +# In your Asterisk server setup you also need to have several things activated +# and defined. See the CONF_Asterisk.txt file for details +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# +# 50810-1547 - Added database server variable definitions lookup +# 50823-1527 - Altered commandline debug options with debug printouts +# 50902-1032 - Changed default logging to fulllog +# + +$FULL_LOG = 1; # set to 1 for a full response log to be created in /home/cron/action_full.date + +$secX = time(); + +($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); +$year = ($year + 1900); +$mon++; +if ($mon < 10) {$mon = "0$mon";} +if ($mday < 10) {$mday = "0$mday";} +if ($hour < 10) {$Fhour = "0$hour";} +if ($min < 10) {$min = "0$min";} +if ($sec < 10) {$sec = "0$sec";} + +$now_date_epoch = time(); +$now_date = "$year-$mon-$mday $hour:$min:$sec"; +$action_log_date = "$year-$mon-$mday"; + +### Make sure this file is in a libs path or put the absolute path to it +require("/home/cron/AST_SERVER_conf.pl"); # local configuration file + +if (!$DB_port) {$DB_port='3306';} + +### begin parsing run-time options ### +if (length($ARGV[0])>1) +{ + $i=0; + while ($#ARGV >= $i) + { + $ARGS = "$ARGS $ARGV[$i]\n"; + $i++; + } + +# print "DB0: |$ARGS|$#ARGV|$i|\n"; + + if ($ARGS =~ /--help/i) + { + print "allowed run time options:\n [-debug] = debug output\n [-debugX] = Extra-debug output\n [-fulllog] = full response logging\n [--data1=XXXXXXX] = vicidial_manager record\n\n\n"; + } + else + { + if ($args =~ /-debug/i) + { + $DB=1; # Debug flag + } + if ($args =~ /--debugX/i) + { + $DBX=1; + print "\n----- SUPER-DUPER DEBUGGING -----\n\n"; + } + if ($args =~ /-fulllog/i) + { + $FULL_LOG=1; # Full response logging enabled + } + if ($ARGS =~ /--data1=/i) + { + $data1 = $ARGS; +# print "DB1: |$ARGS|\n"; + $data1 =~ s/^.*--data1=//gi; +# print "DB2: |$data1|\n"; + $data1 =~ s/ .*$//gi; +# print "DB3: |$data1|\n"; + } + + } +} +else +{ +#print "no command line options set\n\n"; +} + +if (length($data1)>1) + { +# print "Data1 value = |$data1|\n"; + +use Net::MySQL; +use Net::Telnet (); + + my $dbhA = Net::MySQL->new(hostname => "$DB_server", database => "$DB_database", user => "$DB_user", password => "$DB_pass", port => "$DB_port") + or die "Couldn't connect to database: $DB_server - $DB_database\n"; + + ### Grab Server values from the database + $stmtA = "SELECT telnet_host,telnet_port,ASTmgrUSERNAME,ASTmgrSECRET,ASTmgrUSERNAMEsend FROM servers where server_ip = '$server_ip';"; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $DBtelnet_host = "$record->[0]"; + $DBtelnet_port = "$record->[1]"; + $DBASTmgrUSERNAME = "$record->[2]"; + $DBASTmgrSECRET = "$record->[3]"; + $DBASTmgrUSERNAMEsend = "$record->[4]"; + if ($DBtelnet_host) {$telnet_host = $DBtelnet_host;} + if ($DBtelnet_port) {$telnet_port = $DBtelnet_port;} + if ($DBASTmgrUSERNAME) {$ASTmgrUSERNAME = $DBASTmgrUSERNAME;} + if ($DBASTmgrSECRET) {$ASTmgrSECRET = $DBASTmgrSECRET;} + if ($DBASTmgrUSERNAMEsend) {$ASTmgrUSERNAMEsend = $DBASTmgrUSERNAMEsend;} + } + } + + + $stmtA = "SELECT * FROM vicidial_manager where man_id = '$data1'"; + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_count=0; + while ( $record = $iter->each) + { + $man_id = "$record->[0]"; + $uniqueid = "$record->[1]"; + $channel = "$record->[6]"; + $action = "$record->[7]"; + $callid = "$record->[8]"; + $cmd_line_b = "$record->[9]"; + $cmd_line_c = "$record->[10]"; + $cmd_line_d = "$record->[11]"; + $cmd_line_e = "$record->[12]"; + $cmd_line_f = "$record->[13]"; + $cmd_line_g = "$record->[14]"; + $cmd_line_h = "$record->[15]"; + $cmd_line_i = "$record->[16]"; + $cmd_line_j = "$record->[17]"; + $cmd_line_k = "$record->[18]"; + + $originate_command = ''; + $originate_command .= "Action: $action\n"; + if (length($cmd_line_b)>3) {$originate_command .= "$cmd_line_b\n";} + if (length($cmd_line_c)>3) {$originate_command .= "$cmd_line_c\n";} + if (length($cmd_line_d)>3) {$originate_command .= "$cmd_line_d\n";} + if (length($cmd_line_e)>3) {$originate_command .= "$cmd_line_e\n";} + if (length($cmd_line_f)>3) {$originate_command .= "$cmd_line_f\n";} + if (length($cmd_line_g)>3) {$originate_command .= "$cmd_line_g\n";} + if (length($cmd_line_h)>3) {$originate_command .= "$cmd_line_h\n";} + if (length($cmd_line_i)>3) {$originate_command .= "$cmd_line_i\n";} + if (length($cmd_line_j)>3) {$originate_command .= "$cmd_line_j\n";} + if (length($cmd_line_k)>3) {$originate_command .= "$cmd_line_k\n";} + $originate_command .= "\n"; + } + } + + $dbhA->close; + + + print "$now_date|$data1|\n$originate_command"; + $event_string = "0|$data1|"; + $event_string .= "\n$originate_command"; + if ($FULL_LOG) {&full_event_logger;} + +if (!$telnet_port) {$telnet_port = '5038';} + + ### connect to asterisk manager through telnet + $tn = new Net::Telnet (Port => $telnet_port, + Prompt => '/.*[\$%#>] $/', + Output_record_separator => '', + Errmode => Return,); + #$fh = $tn->dump_log("$MStelnetlog"); # uncomment for telnet log + if (length($ASTmgrUSERNAMEsend) > 3) {$telnet_login = $ASTmgrUSERNAMEsend;} + else {$telnet_login = $ASTmgrUSERNAME;} + $tn->open("$telnet_host"); + $tn->waitfor('/0\n$/'); # print login + $tn->print("Action: Login\nUsername: $telnet_login\nSecret: $ASTmgrSECRET\n\n"); + $tn->waitfor('/Authentication accepted/'); # waitfor auth accepted + + $tn->buffer_empty; + + @list_channels = $tn->cmd(String => "$originate_command", Prompt => '/.*/'); + +sleep(3); + + if ($FULL_LOG) + { + $event_string = "1|$data1|"; $k=0; + foreach(@list_channels) {$event_string .= "$list_channels[$k]"; $k++;} + $read_input_buf = $tn->get(Errmode => Return, Timeout => 1,); + $event_string .= "$read_input_buf"; + &full_event_logger; + } + + $tn->buffer_empty; + + @hangup = $tn->cmd(String => "Action: Logoff\n\n", Prompt => "/.*/"); + +sleep(2); + + if ($FULL_LOG) + { + $event_string = "2|$data1|"; $k=0; + foreach(@list_channels) {$event_string .= "$list_channels[$k]"; $k++;} + $read_input_buf = $tn->get(Errmode => Return, Timeout => 1,); + $event_string .= "$read_input_buf"; + &full_event_logger; + } + + $tn->buffer_empty; + + $ok = $tn->close; + + + + + } + +$secZ = time(); +$script_time = ($secZ - $secX); +print "DONE execute time: $script_time seconds\n"; + +exit; + +sub full_event_logger { + ### open the log file for writing ### + open(Lout, ">>/home/cron/action_full.$action_log_date") + || die "Can't open /home/cron/action_full.$action_log_date: $!\n"; + + print Lout "$now_date|$event_string|\n"; + + close(Lout); + +$event_string=''; +} diff --git a/AST_update.pl b/AST_update.pl new file mode 100644 index 00000000..12f0a053 --- /dev/null +++ b/AST_update.pl @@ -0,0 +1,1110 @@ +#!/usr/bin/perl +# +# AST_update.pl version 1.1.11 (build 60411-1032) +# +# DESCRIPTION: +# uses the Asterisk Manager interface and Net::MySQL to update the live_channels +# tables and verify the parked_channels table in the asterisk MySQL database +# This "near-live-status of Zap/SIP/Local/IAX channels" list is used by clients +# +# SUMMARY: +# This program was designed for people using the Asterisk PBX with Digium +# Zaptel telco cards and SIP VOIP hardphones or softphones as extensions, it +# could be adapted to other functions, but I designed it specifically for +# Zap/IAX2/SIP users. The program will run on UNIX or Win32 command line +# providing the following criteria are met: +# +# Win32 - ActiveState Perl 5.8.0 +# UNIX - Gnome or KDE with Tk/Tcl and perl Tk/Tcl modules loaded +# Both - Net::MySQL, Net::Telnet and Time::HiRes perl modules loaded +# +# For the client program to work, this program must always be running +# +# For this program to work you need to have the "asterisk" MySQL database +# created and create the tables listed in the MySQL_AST_CREATE_tables.sql file, +# also make sure that the machine running this program has select/insert/update/delete +# access to that database +# +# In your Asterisk server setup you also need to have several things activated +# and defined. See the CONF_Asterisk.txt file for details +# +# It is recommended that you run this program on the local Asterisk machine +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# +# version changes: +# 41228-1659 - modified to compensate for manager output response hiccups +# 50107-1611 - modified to add Zap and IAX2 clients (differentiate from trunks) +# 50117-1537 - modified to add MySQL port ($DB_port) var from conf file +# 50303-0958 - modified to compensate for Zap manager output hiccups +# 50406-1320 - added channel_data to live_channels table for more flexibility +# also added Zap/IAX client check every 100 loop instead of only once +# 50509-1047 - added collection of server_performance data with SYSPERF flag +# 50621-1307 - modified to allow for SIP trunks +# 50810-1601 - Added database server variable definitions lookup +# 50823-1625 - Altered Debug vars and initial CVS/1.2 support for changed output +# 50824-1606 - Altered CVS/1.2 support for "show channels concise" output +# 50829-1134 - Added processor percentage usage to stat collection +# 51229-1355 - Added ability to take ! as delimited for 1.2 show channels concise +# 60117-1202 - Changed IAX2 client phone channel to reflect change to '-' iteration +# 60411-1032 - Fixed bug in test section that caused crash with ** in extension +# + +$build = '60411-1032'; + +# constants +$SYSPERF=0; # system performance logging to MySQL server_performance table every 5 seconds +$SYSPERF_rec=0; # is dial-time recording turned on +$DB=0; # Debug flag, set to 1 for debug messages WARNING LOTS OF OUTPUT!!! +$DBX=0; # Debug flag, set to 1 for debug messages WARNING LOTS OF OUTPUT!!! +$US='__'; +$AMP='@'; +$MT[0]=''; +$cpuUSERprev=0; +$cpuSYSTprev=0; +$cpuIDLEprev=0; + +# DB table variables for testing + $parked_channels = 'parked_channels'; + $live_channels = 'live_channels'; + $live_sip_channels = 'live_sip_channels'; + $server_updater = 'server_updater'; +# $parked_channels = 'TEST_parked_channels'; +# $live_channels = 'TEST_live_channels'; +# $live_sip_channels = 'TEST_live_sip_channels'; +# $server_updater = 'TEST_server_updater'; + +### begin parsing run-time options ### +if (length($ARGV[0])>1) +{ + $i=0; + while ($#ARGV >= $i) + { + $args = "$args $ARGV[$i]"; + $i++; + } + + if ($args =~ /--help/i) + { + print "allowed run time options:\n [-t] = test\n [-sysperf] = system performance logging\n [-sysperfdebug] = system performance debug output\n [-debug] = verbose debug messages\n [-debugX] = Extra-verbose debug messages\n\n"; + exit; + } + else + { + if ($args =~ /-sysperf/i) + { + $SYSPERF=1; # System performance logging flag + } + if ($args =~ /-sysperfdebug/i) + { + $SYSPERFDB=1; # prints system performance data out to STDOUT + } + if ($args =~ /-debug/i) + { + $DB=1; # Debug flag + } + if ($args =~ /--debugX/i) + { + $DBX=1; + print "\n----- SUPER-DUPER DEBUGGING -----\nBUILD: $build\n"; + } + if ($args =~ /-t/i) + { + $TEST=1; + $T=1; + } + } +} +else +{ +# print "no command line options set\n"; +} +### end parsing run-time options ### + + + +### Make sure this file is in a libs path or put the absolute path to it +require("/home/cron/AST_SERVER_conf.pl"); # local configuration file + +if (!$DB_port) {$DB_port='3306';} + + &get_time_now; + + $event_string='PROGRAM STARTED||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||'; + &event_logger; + +use lib './lib', '../lib'; +use Time::HiRes ('gettimeofday','usleep','sleep'); # necessary to have perl sleep command of less than one second +use Net::MySQL; +use Net::Telnet (); + + my $dbhA = Net::MySQL->new(hostname => "$DB_server", database => "$DB_database", user => "$DB_user", password => "$DB_pass", port => "$DB_port") + or die "Couldn't connect to database: $DB_server - $DB_database\n"; + + $event_string='LOGGED INTO MYSQL SERVER ON 1 CONNECTION|'; + &event_logger; + +### Grab Server values from the database +$stmtA = "SELECT telnet_host,telnet_port,ASTmgrUSERNAME,ASTmgrSECRET,ASTmgrUSERNAMEupdate,ASTmgrUSERNAMElisten,ASTmgrUSERNAMEsend,max_vicidial_trunks,answer_transfer_agent,local_gmt,ext_context,asterisk_version FROM servers where server_ip = '$server_ip';"; +$dbhA->query("$stmtA"); +if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $DBtelnet_host = "$record->[0]"; + $DBtelnet_port = "$record->[1]"; + $DBASTmgrUSERNAME = "$record->[2]"; + $DBASTmgrSECRET = "$record->[3]"; + $DBASTmgrUSERNAMEupdate = "$record->[4]"; + $DBASTmgrUSERNAMElisten = "$record->[5]"; + $DBASTmgrUSERNAMEsend = "$record->[6]"; + $DBmax_vicidial_trunks = "$record->[7]"; + $DBanswer_transfer_agent= "$record->[8]"; + $DBSERVER_GMT = "$record->[9]"; + $DBext_context = "$record->[10]"; + $DBasterisk_version = "$record->[11]"; + if ($DBtelnet_host) {$telnet_host = $DBtelnet_host;} + if ($DBtelnet_port) {$telnet_port = $DBtelnet_port;} + if ($DBASTmgrUSERNAME) {$ASTmgrUSERNAME = $DBASTmgrUSERNAME;} + if ($DBASTmgrSECRET) {$ASTmgrSECRET = $DBASTmgrSECRET;} + if ($DBASTmgrUSERNAMEupdate) {$ASTmgrUSERNAMEupdate = $DBASTmgrUSERNAMEupdate;} + if ($DBASTmgrUSERNAMElisten) {$ASTmgrUSERNAMElisten = $DBASTmgrUSERNAMElisten;} + if ($DBASTmgrUSERNAMEsend) {$ASTmgrUSERNAMEsend = $DBASTmgrUSERNAMEsend;} + if ($DBmax_vicidial_trunks) {$max_vicidial_trunks = $DBmax_vicidial_trunks;} + if ($DBanswer_transfer_agent) {$answer_transfer_agent = $DBanswer_transfer_agent;} + if ($DBSERVER_GMT) {$SERVER_GMT = $DBSERVER_GMT;} + if ($DBext_context) {$ext_context = $DBext_context;} + if ($DBasterisk_version) {$AST_ver = $DBasterisk_version;} + } + } + + if ($AST_ver =~ /^1\.2|^CVS|^SVN/i) {$show_channels_12_format = 1;} + else {$show_channels_12_format = 0;} + +##### LOOK FOR ZAP CLIENTS AS DEFINED IN THE phones TABLE SO THEY ARE NOT MISLABELED AS TRUNKS + print STDERR "LOOKING FOR Zap clients assigned to this server:\n"; + $Zap_client_count=0; + $Zap_client_list='|'; + $stmtA = "SELECT extension FROM phones where protocol = 'Zap' and server_ip='$server_ip'"; + if($DB){print STDERR "|$stmtA|\n";} + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + print STDERR $record->[0],"\n"; + $Zap_client_list .= "$record->[0]|"; + $Zap_client_count++; + } + } + +##### LOOK FOR IAX2 CLIENTS AS DEFINED IN THE phones TABLE SO THEY ARE NOT MISLABELED AS TRUNKS + print STDERR "LOOKING FOR IAX2 clients assigned to this server:\n"; + $IAX2_client_count=0; + $IAX2_client_list='|'; + $stmtA = "SELECT extension FROM phones where protocol = 'IAX2' and server_ip='$server_ip'"; + if($DB){print STDERR "|$stmtA|\n";} + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + print STDERR $record->[0],"\n"; + $IAX2_client_list .= "$record->[0]|"; + if ($record->[0] !~ /\@/) + {$IAX2_client_list .= "$record->[0]$AMP$record->[0]|";} + else + { + $IAX_user = $record->[0]; + $IAX_user =~ s/\@.*$//gi; + $IAX2_client_list .= "$IAX_user|"; + } + $IAX2_client_count++; + } + } + +##### LOOK FOR SIP CLIENTS AS DEFINED IN THE phones TABLE SO THEY ARE NOT MISLABELED AS TRUNKS + print STDERR "LOOKING FOR SIP clients assigned to this server:\n"; + $SIP_client_count=0; + $SIP_client_list='|'; + $stmtA = "SELECT extension FROM phones where protocol = 'SIP' and server_ip='$server_ip'"; + if($DB){print STDERR "|$stmtA|\n";} + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + print STDERR $record->[0],"\n"; + $SIP_client_list .= "$record->[0]|"; + if ($record->[0] !~ /\@/) + {$SIP_client_list .= "$record->[0]$AMP$record->[0]|";} + else + { + $SIP_user = $record->[0]; + $SIP_user =~ s/\@.*$//gi; + $SIP_client_list .= "$SIP_user|"; + } + $SIP_client_count++; + } + } + + print STDERR "Zap Clients: $Zap_client_list\n"; + print STDERR "IAX2 Clients: $IAX2_client_list\n"; + print STDERR "SIP Clients: $SIP_client_list\n"; + +$one_day_interval = 12; # 2 hour loops for one day +while($one_day_interval > 0) +{ + + $event_string="STARTING NEW MANAGER TELNET CONNECTION||ATTEMPT|ONE DAY INTERVAL:$one_day_interval|"; + &event_logger; + +if (!$telnet_port) {$telnet_port = '5038';} + + ### connect to asterisk manager through telnet + $t = new Net::Telnet (Port => $telnet_port, + Prompt => '/.*[\$%#>] $/', + Output_record_separator => '',); + #$fh = $t->dump_log("$telnetlog"); # uncomment for telnet log + if (length($ASTmgrUSERNAMEupdate) > 3) {$telnet_login = $ASTmgrUSERNAMEupdate;} + else {$telnet_login = $ASTmgrUSERNAME;} + $t->open("$telnet_host"); + $t->waitfor('/0\n$/'); # print login + $t->print("Action: Login\nUsername: $telnet_login\nSecret: $ASTmgrSECRET\n\n"); + $t->waitfor('/Authentication accepted/'); # waitfor auth accepted + + $event_string="STARTING NEW MANAGER TELNET CONNECTION|$telnet_login|CONFIRMED CONNECTION|ONE DAY INTERVAL:$one_day_interval|"; + &event_logger; + + $endless_loop=5769999; # 30 days minutes at .45 seconds per loop + + while($endless_loop > 0) + { + + + @DBchannels=@MT; + @DBsips=@MT; + @list_channels=@MT; + @test_channels=@MT; + + &get_current_channels; + + &validate_parked_channels; + + + $t->buffer_empty; + if (!$show_channels_12_format) + { + @list_channels = $t->cmd(String => "Action: Command\nCommand: show channels\n\n", Prompt => '/--END COMMAND-.*/'); + } + else + { + @list_channels = $t->cmd(String => "Action: Command\nCommand: show channels concise\n\n", Prompt => '/--END COMMAND-.*/'); + } + + ##### TEST CHANNELS ZAP/IAX2/Local TO SEE IF THERE WAS A LARGE HICCUP IN OUTPUT FROM PREVIOUS OUTPUT + @test_channels=@list_channels; + $test_zap_count=0; + $test_iax_count=0; + $test_local_count=0; + $test_sip_count=0; + $s=0; + foreach(@test_channels) + { + chomp($test_channels[$s]); + if($DBX){print "$s|$test_channels[$s]\n";} + $test_channels[$s] =~ s/Congestion\s+\(Empty\)/ SIP\/CONGEST/gi; + $test_channels[$s] =~ s/\(Outgoing Line\)|\(None\)/SIP\/ring/gi; + $test_channels[$s] =~ s/\(Empty\)/SIP\/internal/gi; + if (!$show_channels_12_format) + { + $test_channels[$s] =~ s/^\s*|\s*$//gi; + $test_channels[$s] =~ s/\(.*\)//gi; + } + else + { + $EXcount = 0; + $EXcount = @{[$test_channels[$s] =~ /\!/g]}; + if ($EXcount > 10) + { + @test_chan_12 = split(/\!/, $test_channels[$s]); + } + else + { + @test_chan_12 = split(/:/, $test_channels[$s]); + } + # @test_chan_12 = split(/:/, $test_channels[$s]); + if (length($test_chan_12[6])<2) {$test_chan_12[6] = 'SIP/ring';} + $test_channels[$s] = "$test_chan_12[0] $test_chan_12[6]"; + } + if ($test_channels[$s] =~ /^Zap|^IAX2|^SIP|^Local/) + { + if ($test_channels[$s] =~ /^(\S+)\s+.+\s+(\S+)$/) + { + $channel = $1; + $extension = $2; + if ($show_channels_12_format) + {$extension =~ s/^.*\(|\).*$//gi;} + $extension =~ s/^SIP\/|-\S+$//gi; + $extension =~ s/\|.*//gi; + if ($channel =~ /^SIP/) {$test_sip_count++;} + if ($channel =~ /^Local/) {$test_local_count++;} + if ($IAX2_client_count) + { + $channel_match=$channel; + $channel_match =~ s/\/\d+$|-\d+$//gi; + $channel_match =~ s/^IAX2\///gi; + if ($IAX2_client_list =~ /\|$channel_match\|/i) {$test_iax_count++;} + } + if ($Zap_client_count) + { + $channel_match=$channel; + $channel_match =~ s/^Zap\///gi; + if ($Zap_client_list =~ /\|$channel_match\|/i) {$test_zap_count++;} + } + } + } + $s++; + } + + + + # $DB_live_lines = ($#DBchannels + $#DBsips); + $DB_live_lines = ($channel_counter + $sip_counter); + if ( (!$DB_live_lines) or ($#list_channels < 2) ) + {$PERCENT_static = 0;} + else + { + $PERCENT_static = ( ($#list_channels / $DB_live_lines) * 100); + $PERCENT_static = sprintf("%6.2f", $PERCENT_static); + } + + if ( (!$test_zap_count) or ($zap_client_counter < 2) ) + {$PERCENT_ZC_static = 0;} + else + { + $PERCENT_ZC_static = ( ($test_zap_count / $zap_client_counter) * 100); + $PERCENT_ZC_static = sprintf("%6.2f", $PERCENT_ZC_static); + } + + if ( (!$test_iax_count) or ($iax_client_counter < 2) ) + {$PERCENT_IC_static = 0;} + else + { + $PERCENT_IC_static = ( ($test_iax_count / $iax_client_counter) * 100); + $PERCENT_IC_static = sprintf("%6.2f", $PERCENT_IC_static); + } + + if ( (!$test_local_count) or ($local_client_counter < 2) ) + {$PERCENT_LC_static = 0;} + else + { + $PERCENT_LC_static = ( ($test_local_count / $local_client_counter) * 100); + $PERCENT_LC_static = sprintf("%6.2f", $PERCENT_LC_static); + } + + if ( (!$test_sip_count) or ($sip_client_counter < 2) ) + {$PERCENT_SC_static = 0;} + else + { + $PERCENT_SC_static = ( ($test_sip_count / $sip_client_counter) * 100); + $PERCENT_SC_static = sprintf("%6.2f", $PERCENT_SC_static); + } + + if ($endless_loop =~ /0$/) + {print "-$now_date $PERCENT_static $#list_channels $#DBchannels:$channel_counter $#DBsips:$sip_counter $PERCENT_ZC_static|$test_zap_count:$zap_client_counter $PERCENT_IC_static|$test_iax_count:$iax_client_counter $PERCENT_LC_static|$test_local_count:$local_client_counter $PERCENT_SC_static|$test_sip_count:$sip_client_counter\n";} + + if ( ( ($PERCENT_static < 10) && ( ($channel_counter > 3) or ($sip_counter > 4) ) ) or + ( ($PERCENT_static < 20) && ( ($channel_counter > 10) or ($sip_counter > 10) ) ) or + ( ($PERCENT_static < 30) && ( ($channel_counter > 20) or ($sip_counter > 20) ) ) or + ( ($PERCENT_static < 40) && ( ($channel_counter > 30) or ($sip_counter > 30) ) ) or + ( ($PERCENT_static < 50) && ( ($channel_counter > 40) or ($sip_counter > 40) ) ) or + ( ($PERCENT_ZC_static < 20) && ( $zap_client_counter > 3 ) ) or + ( ($PERCENT_ZC_static < 40) && ( $zap_client_counter > 9 ) ) or + ( ($PERCENT_IC_static < 20) && ( $iax_client_counter > 3 ) ) or + ( ($PERCENT_IC_static < 40) && ( $iax_client_counter > 9 ) ) or + ( ($PERCENT_SC_static < 20) && ( $sip_client_counter > 3 ) ) or + ( ($PERCENT_SC_static < 40) && ( $sip_client_counter > 9 ) ) ) + { + $UD_bad_grab++; + $event_string="------ UPDATER BAD GRAB!!! UBGcount: $UD_bad_grab\n $PERCENT_static $#list_channels $#DBchannels:$channel_counter $#DBsips:$sip_counter $PERCENT_ZC_static|$test_zap_count:$zap_client_counter $PERCENT_IC_static|$test_iax_count:$iax_client_counter $PERCENT_LC_static|$test_local_count:$local_client_counter $PERCENT_SC_static|$test_sip_count:$sip_client_counter\n"; + print "$event_string\n"; + &event_logger; + if ($UD_bad_grab > 20) {$UD_bad_grab=0;} + } + else + { + $UD_bad_grab=0; + if ( ($endless_loop =~ /0$/) && ($SYSPERF) ) + { + $cpuUSERcent=0; $cpuSYSTcent=0; $cpuIDLEcent=0; + ### get processor usage seconds ### + # cpu 924841 211725 270473 6961811 + @cpuUSE = `/usr/bin/cat /proc/stat`; + if ($cpuUSE[0] =~ /cpu\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/) + { + $cpuUSER = ($1 + $2); + $cpuSYST = $3; + $cpuIDLE = $4; + $cpuUSERdiff = ($cpuUSER - $cpuUSERprev); + $cpuSYSTdiff = ($cpuSYST - $cpuSYSTprev); + $cpuIDLEdiff = ($cpuIDLE - $cpuIDLEprev); + $cpuIDLEdiffTOTAL = (($cpuUSERdiff + $cpuSYSTdiff) + $cpuIDLEdiff); + if ($cpuIDLEdiffTOTAL > 0) + { + $cpuUSERcent = sprintf("%.0f", (($cpuUSERdiff / $cpuIDLEdiffTOTAL) * 100)); + $cpuSYSTcent = sprintf("%.0f", (($cpuSYSTdiff / $cpuIDLEdiffTOTAL) * 100)); + $cpuIDLEcent = sprintf("%.0f", (($cpuIDLEdiff / $cpuIDLEdiffTOTAL) * 100)); + } + $cpuUSERprev=$cpuUSER; + $cpuSYSTprev=$cpuSYST; + $cpuIDLEprev=$cpuIDLE; + } + + ### get system load ### + $serverLOAD = `/usr/bin/cat /proc/loadavg`; + $serverLOAD =~ s/ .*//gi; + $serverLOAD =~ s/\D//gi; + + ### get memory usage ### + @GRABserverMEMORY = `/usr/bin/free -m -t`; + if ($GRABserverMEMORY[1] =~ /Mem:\s+(\d+)\s+(\d+)\s+(\d+)\s+/) + { + $MEMused = $2; + $MEMfree = $3; + } + ### get number of system processes ### + @GRABserverPROCESSES = `/bin/ps -A --no-heading`; + $serverPROCESSES = $#GRABserverPROCESSES; + + if ($SYSPERF_rec) {$recording_count = ($test_local_count / 2)} + else {$recording_count=0;} + + if ($SYSPERFDB) + {print "$serverLOAD $MEMfree $MEMused $serverPROCESSES $#list_channels $cpuUSERcent $cpuSYSTcent $cpuIDLEcent\n";} + + $stmtA = "INSERT INTO server_performance (start_time,server_ip,sysload,freeram,usedram,processes,channels_total,trunks_total,clients_total,clients_zap,clients_iax,clients_local,clients_sip,live_recordings,cpu_user_percent,cpu_system_percent,cpu_idle_percent) values('$now_date','$server_ip','$serverLOAD','$MEMfree','$MEMused','$serverPROCESSES','$#list_channels','$channel_counter','$sip_counter','$test_zap_count','$test_iax_count','$test_local_count','$test_sip_count','$recording_count','$cpuUSERcent','$cpuSYSTcent','$cpuIDLEcent')"; + if( ($DB) or ($UD_bad_grab) ){print STDERR "\n|$stmtA|\n";} + $dbhA->query($stmtA) or die "Couldn't execute query: |$stmtA|\n"; + } + } + + if ($endless_loop =~ /00$/) + { + ##### LOOK FOR ZAP CLIENTS AS DEFINED IN THE phones TABLE SO THEY ARE NOT MISLABELED AS TRUNKS + print STDERR "LOOKING FOR Zap clients assigned to this server:\n"; + $Zap_client_count=0; + $Zap_client_list='|'; + $stmtA = "SELECT extension FROM phones where protocol = 'Zap' and server_ip='$server_ip'"; + if($DB){print STDERR "|$stmtA|\n";} + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + print STDERR $record->[0],"\n"; + $Zap_client_list .= "$record->[0]|"; + $Zap_client_count++; + } + } + + ##### LOOK FOR IAX2 CLIENTS AS DEFINED IN THE phones TABLE SO THEY ARE NOT MISLABELED AS TRUNKS + print STDERR "LOOKING FOR IAX2 clients assigned to this server:\n"; + $IAX2_client_count=0; + $IAX2_client_list='|'; + $stmtA = "SELECT extension FROM phones where protocol = 'IAX2' and server_ip='$server_ip'"; + if($DB){print STDERR "|$stmtA|\n";} + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + print STDERR $record->[0],"\n"; + $IAX2_client_list .= "$record->[0]|"; + if ($record->[0] !~ /\@/) + {$IAX2_client_list .= "$record->[0]$AMP$record->[0]|";} + else + { + $IAX_user = $record->[0]; + $IAX_user =~ s/\@.*$//gi; + $IAX2_client_list .= "$IAX_user|"; + } + $IAX2_client_count++; + } + } + + ##### LOOK FOR SIP CLIENTS AS DEFINED IN THE phones TABLE SO THEY ARE NOT MISLABELED AS TRUNKS + print STDERR "LOOKING FOR SIP clients assigned to this server:\n"; + $SIP_client_count=0; + $SIP_client_list='|'; + $stmtA = "SELECT extension FROM phones where protocol = 'SIP' and server_ip='$server_ip'"; + if($DB){print STDERR "|$stmtA|\n";} + $dbhA->query("$stmtA"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + print STDERR $record->[0],"\n"; + $SIP_client_list .= "$record->[0]|"; + if ($record->[0] !~ /\@/) + {$SIP_client_list .= "$record->[0]$AMP$record->[0]|";} + else + { + $SIP_user = $record->[0]; + $SIP_user =~ s/\@.*$//gi; + $SIP_client_list .= "$SIP_user|"; + } + $SIP_client_count++; + } + } + + + print STDERR "Zap Clients: $Zap_client_list\n"; + print STDERR "IAX2 Clients: $IAX2_client_list\n"; + print STDERR "SIP Clients: $SIP_client_list\n"; + } + + @list_chan_12=@MT; + $EXcount = 0; + $EXcount = @{[$list_channels[2] =~ /\!/g]}; + if ($EXcount > 10) + { + @list_chan_12 = split(/\!/, $list_channels[2]); + } + else + { + @list_chan_12 = split(/:/, $list_channels[2]); + } + if( ($DB) && ($show_channels_12_format) ) {print "concise: $#list_chan_12\n";} + if ( ( ( ($list_channels[1] =~ /State Appl\./) or ($list_channels[2] =~ /State Appl\.|Application\(Data\)/) or ($list_channels[3] =~ /State Appl\.|Application\(Data\)/) ) || ($#list_chan_12 > 8) ) && (!$UD_bad_grab) ) + { + + $c=0; + if($DB){print "lines: $#list_channels\n";} + if($DB){print "DBchn: $#DBchannels\n";} + if($DB){print "DBsip: $#DBsips\n";} + foreach(@list_channels) + { + # $DBchannels =~ s/^\|//g; + + chomp($list_channels[$c]); + if( ($DB) or ($UD_bad_grab) ){print "-|$c|$list_channels[$c]|\n";} + $list_channels[$c] =~ s/Congestion\s+\(Empty\)/ SIP\/CONGEST/gi; + $list_channels[$c] =~ s/\(Outgoing Line\)|\(None\)/SIP\/ring/gi; + $list_channels[$c] =~ s/\(Empty\)/SIP\/internal/gi; + if (!$show_channels_12_format) + { + $list_channels[$c] =~ s/^\s*|\s*$//gi; + $list_channels[$c] =~ s/\(.*\)//gi; + } + else + { + @list_chan_12=@MT; + if ($EXcount > 10) + { + @list_chan_12 = split(/\!/, $list_channels[$c]); + } + else + { + @list_chan_12 = split(/:/, $list_channels[$c]); + } + if ($DBX) {print "EXcount: $EXcount\n";} + if (length($list_chan_12[6])<2) {$list_chan_12[6] = 'SIP/ring';} + $list_channels[$c] = "$list_chan_12[0] $list_chan_12[6]"; + } + $list_SIP[$c] = $list_channels[$c]; + if( ($DB) or ($UD_bad_grab) ){print "+|$c|$list_channels[$c]|\n\n";} + + ########## PARSE EACH LINE TO DETERMINE WHETHER IT IS TRUNK OR CLIENT AND PUT IN APPROPRIATE TABLE + if ($list_channels[$c] =~ /^Zap|^IAX2|^SIP|^Local/) + { + if ($list_channels[$c] =~ /^(\S+)\s+.+\s+(\S+)$/) + { + $line_type = ''; + $channel = $1; + $extension = $2; + $channel_data = $extension; + if ($show_channels_12_format) + { + $extension =~ s/^.*\(|\).*$//gi; + #### new data in 1.2 for future use + # SIP/cc160-7b91:default:917274514920:3:Up:Dial:Zap/g2/17274514920|30|o:cc160::3:9:Zap/25-1 + # Zap/30-1:demo:010*010*010*012*8600091:1:Up:Dial:IAX2/TESTast2:test@10.10.10.12:4569/8600051|25|o:::3:123:IAX2/TESTast2-29 + # Zap/9-1:demo:990009*CL_UMGCOF_L**6317906**9545541833*13678*:2:Up:Dial:Zap/r3/90009*CL_UMGCOF_L**6317906**9545541833*13678*|120|o:::3:334:Zap/82-1 + # $channel = $list_chan_12[0]; + # $channel_data = $list_chan_12[0]; + # $context = $list_chan_12[1]; + # $dialed = $list_chan_12[2]; + # $priority = $list_chan_12[3]; + # $state = $list_chan_12[4]; + # $extension = $list_chan_12[6]; + # $callerid = $list_chan_12[7]; + # $duration = $list_chan_12[10]; + # $bridged = $list_chan_12[11]; + } + $extension =~ s/^SIP\/|-\S+$//gi; + $extension =~ s/\|.*//gi; + $QRYchannel = "$channel$US$extension"; + + if( ($DB) or ($UD_bad_grab) ){print "channel: |$channel|\n";} + if( ($DB) or ($UD_bad_grab) ){print "extension: |$extension|\n";} + if( ($DB) or ($UD_bad_grab) ){print "QRYchannel:|$QRYchannel|\n";} + + if ($channel =~ /^SIP|^Zap|^IAX2/) {$line_type = 'TRUNK';} + if ($channel =~ /^Local/) {$line_type = 'CLIENT';} + if ($IAX2_client_count) + { + $channel_match=$channel; + $channel_match =~ s/\/\d+$|-\d+$//gi; + $channel_match =~ s/^IAX2\///gi; + # print "checking for IAX2 client: |$channel_match|\n"; + if ($IAX2_client_list =~ /\|$channel_match\|/i) {$line_type = 'CLIENT';} + } + if ($Zap_client_count) + { + $channel_match=$channel; + $channel_match =~ s/^Zap\///gi; + # print "checking for Zap client: |$channel_match|\n"; + if ($Zap_client_list =~ /\|$channel_match\|/i) {$line_type = 'CLIENT';} + } + if ($SIP_client_count) + { + $channel_match=$channel; + $channel_match =~ s/-\S+$//gi; + $channel_match =~ s/^SIP\///gi; + # print "checking for SIP client: |$channel_match|\n"; + if ($SIP_client_list =~ /\|$channel_match\|/i) {$line_type = 'CLIENT';} + } + + if ($line_type eq 'TRUNK') + { + if( ($DB) or ($UD_bad_grab) ){print "current channels: $#DBchannels\n";} + + $k=0; + $channel_in_DB=0; + foreach(@DBchannels) + { + if ( ($DBchannels[$k] eq "$QRYchannel") && (!$channel_in_DB) ) + { + $DBchannels[$k] = ''; + $channel_in_DB++; + } + if( ($DB) or ($UD_bad_grab) ){print "DB $k|$DBchannels[$k]| |";} + $k++; + } + + if ( (!$channel_in_DB) && (length($QRYchannel)>3) ) + { + $stmtA = "INSERT INTO $live_channels (channel,server_ip,extension,channel_data) values('$channel','$server_ip','$extension','$channel_data')"; + if( ($DB) or ($UD_bad_grab) ){print STDERR "\n|$stmtA|\n";} + $dbhA->query($stmtA) or die "Couldn't execute query: |$stmtA|\n"; + } + } + + if ($line_type eq 'CLIENT') + { + if( ($DB) or ($UD_bad_grab) ){print "current sips: $#DBsips\n";} + + $k=0; + $sipchan_in_DB=0; + foreach(@DBsips) + { + if ( ($DBsips[$k] eq "$QRYchannel") && (!$sipchan_in_DB) ) + { + $DBsips[$k] = ''; + $sipchan_in_DB++; + } + if( ($DB) or ($UD_bad_grab) ){print "DB $k|$DBsips[$k]| |";} + $k++; + } + + if ( (!$sipchan_in_DB) && (length($QRYchannel)>3) ) + { + $stmtA = "INSERT INTO $live_sip_channels (channel,server_ip,extension,channel_data) values('$channel','$server_ip','$extension','$channel_data')"; + if( ($DB) or ($UD_bad_grab) ){print STDERR "\n|$stmtA|\n";} + $dbhA->query($stmtA) or die "Couldn't execute query: |$stmtA|\n"; + } + } + } + } + + $c++; + } + if($DB){print "COUNT: $c|$#list_channels|$endless_loop\n";} + + + if ($#DBchannels >= 0) + { + $d=0; + foreach(@DBchannels) + { + if (length($DBchannels[$d])>4) + { + ($DELchannel, $DELextension) = split(/\_\_/, $DBchannels[$d]); + $stmtB = "DELETE FROM $live_channels where server_ip='$server_ip' and channel='$DELchannel' and extension='$DELextension' limit 1"; + if( ($DB) or ($UD_bad_grab) ){print STDERR "\n|$stmtB|\n";} + $dbhA->query($stmtB); + # $dbhA->query($stmtB) or die "Couldn't execute query:\n"; + } + $d++; + } + } + + if ($#DBsips >= 0) + { + $d=0; + foreach(@DBsips) + { + if (length($DBsips[$d])>4) + { + ($DELchannel, $DELextension) = split(/\_\_/, $DBsips[$d]); + $stmtB = "DELETE FROM $live_sip_channels where server_ip='$server_ip' and channel='$DELchannel' and extension='$DELextension' limit 1"; + if( ($DB) or ($UD_bad_grab) ){print STDERR "\n|$stmtB|\n";} + $dbhA->query($stmtB); + # $dbhA->query($stmtB) or die "Couldn't execute query:\n"; + } + $d++; + } + } + + ### sleep for 45 hundredths of a second + usleep(1*450*1000); + + $endless_loop--; + if($DB){print STDERR "\nloop counter: |$endless_loop|\n";} + + ### putting a blank file called "update.kill" in a directory will automatically safely kill this program + if (-e '/home/cron/update.kill') + { + unlink('/home/cron/update.kill'); + $endless_loop=0; + $one_day_interval=0; + print "\nPROCESS KILLED MANUALLY... EXITING\n\n" + } + + $bad_grabber_counter=0; + $no_channels_12_counter=0; + } + + else + { + if ( ($list_channels[1] !~ /Privilege: Command/) && ($show_channels_12_format) ) + { + $bad_grabber_counter++; + if($DB){print STDERR "\nbad grab, trying again\n";} + ### sleep for 20 hundredths of a second + usleep(1*200*1000); + + $event_string="BAD GRAB TRYING AGAIN|BAD_GRABS: $bad_grabber_counter|$endless_loop|ONE DAY INTERVAL:$one_day_interval|"; + &event_logger; + + if ($bad_grabber_counter > 100) + { + $endless_loop=0; + $event_string="TOO MANY BAD GRABS, STARTING NEW CONNECTION|BAD_GRABS: $bad_grabber_counter|$endless_loop|ONE DAY INTERVAL:$one_day_interval|"; + &event_logger; + $bad_grabber_counter=0; + } + } + else + { + $no_channels_12_counter++; + $event_string="NO CHANNELS HERE|COUNTER: $no_channels_12_counter|$endless_loop|ONE DAY INTERVAL:$one_day_interval|$list_channels[1]"; + &event_logger; + + if($DBX) {print "*|EMPTY CHANNELS: $no_channels_12_counter|$#list_channels|$list_channels[1]";} + + ### sleep for 40 hundredths of a second + usleep(1*400*1000); + if ($no_channels_12_counter == 3) + { + ### there are no channels, delete all from live_channels, live_sip_channels + $event_string="NO CHANNELS HERE|COUNTER: $no_channels_12_counter|$endless_loop|ONE DAY INTERVAL:$one_day_interval|$list_channels[1]"; + &event_logger; + $stmtB = "DELETE FROM $live_sip_channels where server_ip='$server_ip'"; + if( ($DB) or ($UD_bad_grab) ){print STDERR "\n|$stmtB|\n";} + $dbhA->query($stmtB); + $stmtB = "DELETE FROM $live_channels where server_ip='$server_ip'"; + if( ($DB) or ($UD_bad_grab) ){print STDERR "\n|$stmtB|\n";} + $dbhA->query($stmtB); + } + + } + } + + + } + + + if($DB){print "DONE... Exiting... Goodbye... See you later... Not really, initiating next loop...\n";} + + $event_string='HANGING UP|'; + &event_logger; + + @hangup = $t->cmd(String => "Action: Logoff\n\n", Prompt => "/.*/"); + + $ok = $t->close; + + $one_day_interval--; + +} + + $event_string='CLOSING DB CONNECTION|'; + &event_logger; + + + $dbhA->close; + + + if($DB){print "DONE... Exiting... Goodbye... See you later... Really I mean it this time\n";} + + +exit; + + + + + + + +####################################################################### +# This subroutine simply grabs all active channel/extension combinations from +# the asterisk MySQL database to be compared to the Asterisk Manager results +####################################################################### +sub get_current_channels +{ +$channel_counter=0; +$sip_counter=0; +$zap_client_counter=0; +$iax_client_counter=0; +$local_client_counter=0; +$sip_client_counter=0; + + if($DB){print STDERR "\n|SELECT channel,extension FROM $live_channels where server_ip = '$server_ip'|\n";} + +$dbhA->query("SELECT channel,extension FROM $live_channels where server_ip = '$server_ip'"); +if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_count=0; + while ( $record = $iter->each) + { + if($DB){print STDERR $record->[0],"|", $record->[1],"\n";} + $DBchannels[$channel_counter] = "$record->[0]$US$record->[1]"; + + $channel_counter++; + $rec_count++; + } + } + +$dbhA->query("SELECT channel,extension FROM $live_sip_channels where server_ip = '$server_ip'"); +if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_count_sip=0; + while ( $record = $iter->each) + { + if($DB){print STDERR $record->[0],"|", $record->[1],"\n";} + $DBsips[$sip_counter] = "$record->[0]$US$record->[1]"; + + if ($record->[0] =~ /^Zap/) {$zap_client_counter++;} + if ($record->[0] =~ /^IAX/) {$iax_client_counter++;} + if ($record->[0] =~ /^Local/) {$local_client_counter++;} + if ($record->[0] =~ /^SIP/) {$sip_client_counter++;} + $sip_counter++; + $rec_count_sip++; + } + } + + &get_time_now; + +$stmtU = "UPDATE $server_updater set last_update='$now_date' where server_ip='$server_ip'"; + if($DB){print STDERR "\n|$stmtU|\n";} +$dbhA->query($stmtU); + +} + + + + + +####################################################################### +# The purpose of this subroutine is to make sure that the calls that are +# listed as parked in the parked_channels table are in fact live (to make +# sure the caller has not hung up) and if the channel is not live to delete +# the parked_channels entry for that specific parked channel entry +# +# Yes it does use two DB connections all by itself, I just did that for speed +# and ease of programming to be backward compatible with MySQL < 4.1 or else +# I would have used a delete with subselect and saved all of this bloated code +####################################################################### +sub validate_parked_channels +{ + +if (!$run_validate_parked_channels_now) + { + + $parked_counter=0; + @ARchannel=@MT; @ARextension=@MT; @ARparked_time=@MT; @ARparked_time_UNIX=@MT; + $dbhA->query("SELECT channel,extension,parked_time,UNIX_TIMESTAMP(parked_time) FROM $parked_channels where server_ip = '$server_ip' order by channel desc, parked_time desc"); + if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_count=0; + while ( $record = $iter->each) + { + $PQchannel = $record->[0]; + $PQextension = $record->[1]; + $PQparked_time = $record->[2]; + $PQparked_time_UNIX = $record->[3]; + if($DB){print STDERR "\n|$PQchannel|$PQextension|$PQparked_time|$PQparked_time_UNIX|\n";} + + my $dbhC = Net::MySQL->new(hostname => "$DB_server", database => "$DB_database", user => "$DB_user", password => "$DB_pass", port => "$DB_port") + or die "Couldn't connect to database: $DB_server - $DB_database\n"; + + + $AR=0; + $record_deleted=0; + foreach(@ARchannel) + { + if (@ARchannel[$AR] eq "$PQchannel") + { + if (@ARparked_time_UNIX[$AR] > $PQparked_time_UNIX) + { + if($DBX){print "Duplicate parked channel delete: |$PQchannel|$PQparked_time|\n";} + $stmtPQ = "DELETE FROM $parked_channels where server_ip='$server_ip' and channel='$PQchannel' and extension='$PQextension' and parked_time='$PQparked_time' limit 1"; + if($DB){print STDERR "\n|$stmtPQ|$$DEL_chan_park_counter|$DEL_chan_park_counter|\n\n";} + $dbhC->query($stmtPQ); + + $DEL_chan_park_counter = "DEL$PQchannel$PQextension"; + $$DEL_chan_park_counter=0; + $record_deleted++; + } + + } + + $AR++; + } + + + + if (!$record_deleted) + { + $ARchannel[$rec_count] = $record->[0]; + $ARextension[$rec_count] = $record->[1]; + $ARparked_time[$rec_count] = $record->[2]; + $ARparked_time_UNIX[$rec_count] = $record->[3]; + + + my $dbhB = Net::MySQL->new(hostname => "$DB_server", database => "$DB_database", user => "$DB_user", password => "$DB_pass", port => "$DB_port") + or die "Couldn't connect to database: $DB_server - $DB_database\n"; + + + $event_string='LOGGED INTO MYSQL SERVER ON 2 CONNECTIONS TO VALIDATE PARKED CALLS|'; + &event_logger; + + + $dbhB->query("SELECT count(*) FROM $live_channels where server_ip='$server_ip' and channel='$PQchannel' and extension='$PQextension'"); + if ($dbhB->has_selected_record) + { + $iterB=$dbhB->create_record_iterator; + $rec_countB=0; + while ( $recordB = $iterB->each) + { + $PQcount = $recordB->[0]; + if($DB){print STDERR "\n|$PQcount|\n";} + + if ($PQcount < 1) + { + $DEL_chan_park_counter = "DEL$PQchannel$PQextension"; + $$DEL_chan_park_counter++; + if($DBX){print STDERR "Parked counter down|$$DEL_chan_park_counter|$DEL_chan_park_counter|\n";} + + ### if the parked channel doesn't exist 6 times then delete it from table + if ($$DEL_chan_park_counter > 5) + { + if($DBX){print " parked channel delete: |$PQchannel|$PQparked_time|\n";} + $stmtPQ = "DELETE FROM $parked_channels where server_ip='$server_ip' and channel='$PQchannel' and extension='$PQextension' limit 1"; + if($DB){print STDERR "\n|$stmtPQ|$$DEL_chan_park_counter|$DEL_chan_park_counter|\n\n";} + $dbhC->query($stmtPQ); + + $ARchannel[$rec_count] = ''; + $ARextension[$rec_count] = ''; + $ARparked_time[$rec_count] = ''; + $ARparked_time_UNIX[$rec_count] = ''; + $$DEL_chan_park_counter=0; + } + } + else + { + $DEL_chan_park_counter = "DEL$PQchannel$PQextension"; + $$DEL_chan_park_counter=0; + } + } + } + + $event_string='CLOSING MYSQL CONNECTIONS OPENED TO VALIDATE PARKED CALLS|'; + &event_logger; + + + $dbhB->close; + + } + + $dbhC->close; + + } + $parked_counter++; + $rec_count++; + } + + $run_validate_parked_channels_now=5; # set to run every five times the subroutine runs + + } + + $run_validate_parked_channels_now--; + +} + + + + + +################################################################################ +##### get the current date and time and epoch for logging call lengths and datetimes +sub get_time_now +{ +($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); +$year = ($year + 1900); +$mon++; +if ($mon < 10) {$mon = "0$mon";} +if ($mday < 10) {$mday = "0$mday";} +if ($hour < 10) {$Fhour = "0$hour";} +if ($min < 10) {$min = "0$min";} +if ($sec < 10) {$sec = "0$sec";} + +$now_date_epoch = time(); +$now_date = "$year-$mon-$mday $hour:$min:$sec"; +} + + + + + +################################################################################ +##### open the log file for writing ### +sub event_logger +{ +open(Lout, ">>$LOGfile") + || die "Can't open $LOGfile: $!\n"; +print Lout "$now_date|$event_string|\n"; +close(Lout); +$event_string=''; +} diff --git a/AST_vm_update.pl b/AST_vm_update.pl new file mode 100644 index 00000000..6125ad70 --- /dev/null +++ b/AST_vm_update.pl @@ -0,0 +1,202 @@ +#!/usr/bin/perl +# +# AST_vm_update.pl version 0.3 +# +# DESCRIPTION: +# uses the Asterisk Manager interface and Net::MySQL to update the count of +# voicemail messages for each mailbox (in the phone table) in the voicemail +# table list is used by client apps for voicemail notification +# +# SUMMARY: +# This program was designed for people using the Asterisk PBX with voicemail +# +# For the client program to notify of new messaged, this program must be in the +# cron running every minute +# +# For this program to work you need to have the "asterisk" MySQL database +# created and create the tables listed in the CONF_MySQL.txt file, also make sure +# that the machine running this program has read/write/update/delete access +# to that database +# +# It is recommended that you run this program on the local Asterisk machine +# +# If this script is run ever minute there is a theoretical limit of +# 600 mailboxes that it can check due to the wait interval. If you have +# more than this either change the cron when this script is run or change the +# wait interval below +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# +# 50823-1422 - Added database server variable definitions lookup +# 50823-1452 - Added commandline arguments for debug at runtime +# + +# constants +$DB=0; # Debug flag, set to 0 for no debug messages per minute +$US='__'; +$MT[0]=''; + +### begin parsing run-time options ### +if (length($ARGV[0])>1) +{ + $i=0; + while ($#ARGV >= $i) + { + $args = "$args $ARGV[$i]"; + $i++; + } + + if ($args =~ /--help/i) + { + print "allowed run time options:\n [-t] = test\n [-debug] = verbose debug messages\n\n"; + } + else + { + if ($args =~ /-debug/i) + { + $DB=1; # Debug flag + } + if ($args =~ /-t/i) + { + $TEST=1; + $T=1; + } + } +} +else +{ +# print "no command line options set\n"; +} +### end parsing run-time options ### + +### Make sure this file is in a libs path or put the absolute path to it +require("/home/cron/AST_SERVER_conf.pl"); # local configuration file + +if (!$DB_port) {$DB_port='3306';} + +use lib './lib', '../lib'; +use Time::HiRes ('gettimeofday','usleep','sleep'); # necessary to have perl sleep command of less than one second +use Net::MySQL; +use Net::Telnet (); + + + my $dbhA = Net::MySQL->new(hostname => "$DB_server", database => "$DB_database", user => "$DB_user", password => "$DB_pass", port => "$DB_port") + or die "Couldn't connect to database: $DB_server - $DB_database\n"; + +### Grab Server values from the database +$stmtA = "SELECT telnet_host,telnet_port,ASTmgrUSERNAME,ASTmgrSECRET,ASTmgrUSERNAMEupdate,ASTmgrUSERNAMElisten,ASTmgrUSERNAMEsend,max_vicidial_trunks,answer_transfer_agent,local_gmt,ext_context FROM servers where server_ip = '$server_ip';"; +$dbhA->query("$stmtA"); +if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + while ( $record = $iter->each) + { + $DBtelnet_host = "$record->[0]"; + $DBtelnet_port = "$record->[1]"; + $DBASTmgrUSERNAME = "$record->[2]"; + $DBASTmgrSECRET = "$record->[3]"; + $DBASTmgrUSERNAMEupdate = "$record->[4]"; + $DBASTmgrUSERNAMElisten = "$record->[5]"; + $DBASTmgrUSERNAMEsend = "$record->[6]"; + $DBmax_vicidial_trunks = "$record->[7]"; + $DBanswer_transfer_agent= "$record->[8]"; + $DBSERVER_GMT = "$record->[9]"; + $DBext_context = "$record->[10]"; + if ($DBtelnet_host) {$telnet_host = $DBtelnet_host;} + if ($DBtelnet_port) {$telnet_port = $DBtelnet_port;} + if ($DBASTmgrUSERNAME) {$ASTmgrUSERNAME = $DBASTmgrUSERNAME;} + if ($DBASTmgrSECRET) {$ASTmgrSECRET = $DBASTmgrSECRET;} + if ($DBASTmgrUSERNAMEupdate) {$ASTmgrUSERNAMEupdate = $DBASTmgrUSERNAMEupdate;} + if ($DBASTmgrUSERNAMElisten) {$ASTmgrUSERNAMElisten = $DBASTmgrUSERNAMElisten;} + if ($DBASTmgrUSERNAMEsend) {$ASTmgrUSERNAMEsend = $DBASTmgrUSERNAMEsend;} + if ($DBmax_vicidial_trunks) {$max_vicidial_trunks = $DBmax_vicidial_trunks;} + if ($DBanswer_transfer_agent) {$answer_transfer_agent = $DBanswer_transfer_agent;} + if ($DBSERVER_GMT) {$SERVER_GMT = $DBSERVER_GMT;} + if ($DBext_context) {$ext_context = $DBext_context;} + } + } + +@PTextensions=@MT; @PTvoicemail_ids=@MT; @PTmessages=@MT; @PTold_messages=@MT; @NEW_messages=@MT; @OLD_messages=@MT; +$dbhA->query("SELECT extension,voicemail_id,messages,old_messages from phones where server_ip='$server_ip'"); +if ($dbhA->has_selected_record) + { + $iter=$dbhA->create_record_iterator; + $rec_count=0; + while ( $record = $iter->each) + { + $PTextensions[$rec_count] = "$record->[0]"; + $PTvoicemail_ids[$rec_count] = "$record->[1]"; + $PTmessages[$rec_count] = "$record->[2]"; + $PTold_messages[$rec_count] = "$record->[3]"; + $rec_count++; + } + } + + +### connect to asterisk manager through telnet +$t = new Net::Telnet (Port => 5038, + Prompt => '/.*[\$%#>] $/', + Output_record_separator => '',); +#$fh = $t->dump_log("$telnetlog"); # uncomment for telnet log + if (length($ASTmgrUSERNAMEsend) > 3) {$telnet_login = $ASTmgrUSERNAMEsend;} + else {$telnet_login = $ASTmgrUSERNAME;} + +$t->open("$telnet_host"); +$t->waitfor('/0\n$/'); # print login +$t->print("Action: Login\nUsername: $telnet_login\nSecret: $ASTmgrSECRET\n\n"); +$t->waitfor('/Authentication accepted/'); # waitfor auth accepted + + +$i=0; +foreach(@PTextensions) + { + @list_channels=@MT; + $t->buffer_empty; + @list_channels = $t->cmd(String => "Action: MailboxCount\nMailbox: $PTvoicemail_ids[$i]\n\nAction: Ping\n\n", Prompt => '/Response: Pong.*/'); + + $j=0; + foreach(@list_channels) + { + if ($list_channels[$j] =~ /Mailbox: $PTvoicemail_ids[$i]/) + { + $NEW_messages[$i] = "$list_channels[$j+1]"; + $NEW_messages[$i] =~ s/NewMessages: |\n//gi; + $OLD_messages[$i] = "$list_channels[$j+2]"; + $OLD_messages[$i] =~ s/OldMessages: |\n//gi; + } + + $j++; + } + + if($DB){print "MailboxCount- $PTvoicemail_ids[$i] NEW:|$NEW_messages[$i]| OLD:|$OLD_messages[$i]| ";} + if ( ($NEW_messages[$i] eq $PTmessages[$i]) && ($OLD_messages[$i] eq $PTold_messages[$i]) ) + { + if($DB){print "MESSAGE COUNT UNCHANGED, DOING NOTHING FOR THIS MAILBOX\n";} + } + else + { + $stmtA = "UPDATE phones set messages='$NEW_messages[$i]', old_messages='$OLD_messages[$i]' where server_ip='$server_ip' and extension='$PTextensions[$i]'"; + if($DB){print STDERR "\n|$stmtA|\n";} + $dbhA->query($stmtA) or die "Couldn't execute query:|$stmtA|\n"; + } + + $i++; + ### sleep for 10 hundredths of a second + usleep(1*100*1000); + } + + +$t->buffer_empty; +@hangup = $t->cmd(String => "Action: Logoff\n\n", Prompt => "/.*/"); +$t->buffer_empty; +$ok = $t->close; + +$dbhA->close; + +if($DB){print "DONE... Exiting... Goodbye... See you later... \n";} + +exit; + + + + diff --git a/DBI-scripts/AST_VDhopper.pl b/DBI-scripts/AST_VDhopper.pl new file mode 100644 index 00000000..414bdded --- /dev/null +++ b/DBI-scripts/AST_VDhopper.pl @@ -0,0 +1,1188 @@ +#!/usr/bin/perl +# +# AST_VDhopper.pl version 0.10 +# *** DBI version *** +# +# DESCRIPTION: +# uses DBD::MySQL to update the VICIDIAL leads hopper for the streamlined +# approach of allocating leads to client machines. +# +# SUMMARY: +# This program was designed for people using the Asterisk PBX with VICIDIAL +# +# For the client to use VICIDIAL, this program must be in the cron running +# every minute +# +# For this program to work you need to have the "asterisk" MySQL database +# created and create the tables listed in the CONF_MySQL.txt file, also make sure +# that the machine running this program has read/write/update/delete access +# to that database +# +# It is recommended that you run this program on the local Asterisk machine +# +# If this script is run ever minute and you are getting close to no leads after +# a minute, you may want to play with the variables below to streamline for +# your usage +# +# Copyright (C) 2006 Matt Florell LICENSE: GPLv2 +# +# 50810-1613 - Added database server variable definitions lookup +# 60215-1106 - Added Scheduled Callback release functionality +# 60228-1623 - Change Callback activation to set the called_since_last_reset=N +# 60228-1735 - Added hopper gmt validation to remove gmt outside of time range +# 60320-0932 - Added inactive lead list hopper deletion (Thanks Vic Jolin) +# 60322-1030 - Added super debug output +# 60418-0947 - Added lead filter per campaign +# 60509-1416 - Rewrite of local_call_time functions +# 60511-1150 - Added inserts into vicidial_campaign_stats table +# 60609-1451 - Added ability to filter by DNC list vicidial_dnc +# 60614-1159 - Added campaign lead recycling ability +# + +# constants +$DB=0; # Debug flag, set to 0 for no debug messages, On an active system this will generate lots of lines of output per minute +$US='__'; +$MT[0]=''; +#$vicidial_hopper='TEST_vicidial_hopper'; # for testing +$vicidial_hopper='vicidial_hopper'; + +# options +$insert_auto_CB_to_hopper = 1; # set to 1 to automatically insert ANYONE callbacks into the hopper + + +($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); +$year = ($year + 1900); +$mon++; +if ($mon < 10) {$mon = "0$mon";} +if ($mday < 10) {$mday = "0$mday";} +if ($hour < 10) {$Fhour = "0$hour";} +if ($min < 10) {$min = "0$min";} +if ($sec < 10) {$sec = "0$sec";} +$now_date = "$year-$mon-$mday $hour:$min:$sec"; +$VDL_date = "$year-$mon-$mday 00:00:01"; + +if (!$VDHLOGfile) {$VDHLOGfile = "/home/cron/hopper.$year-$mon-$mday";} + +### begin parsing run-time options ### +if (length($ARGV[0])>1) +{ + $i=0; + while ($#ARGV >= $i) + { + $args = "$args $ARGV[$i]"; + $i++; + } + + if ($args =~ /--help/i) + { + print "allowed run time options(must stay in this order):\n [--debug] = debug\n [--debugX] = super debug\n [--dbgmt] = show GMT offset of records as they are inserted into hopper\n [-t] = test\n [--level=XXX] = force a hopper_level of XXX\n [--campaign=XXX] = run for campaign XXX only\n\n"; + } + else + { + if ($args =~ /--campaign=/i) + { + # print "\n|$ARGS|\n\n"; + @data_in = split(/--campaign=/,$args); + $CLIcampaign = $data_in[1]; + } + else + {$CLIcampaign = '';} + if ($args =~ /--level=/i) + { + @data_in = split(/--level=/,$args); + $CLIlevel = $data_in[1]; + $CLIlevel =~ s/ .*$//gi; + $CLIlevel =~ s/\D//gi; + print "\n-----HOPPER LEVEL OVERRIDE: $CLIlevel -----\n\n"; + } + else + {$CLIlevel = '';} + if ($args =~ /--debug/i) + { + $DB=1; + print "\n----- DEBUG -----\n\n"; + } + if ($args =~ /--debugX/i) + { + $DBX=1; + print "\n----- SUPER DEBUG -----\n\n"; + } + if ($args =~ /--dbgmt/i) + { + $DB_show_offset=1; + print "\n-----DEBUG GMT -----\n\n"; + } + if ($args =~ /-t/i) + { + $T=1; $TEST=1; + print "\n-----TESTING -----\n\n"; + } + if ($args =~ /--wipe-hopper-clean/i) + { + $wipe_hopper_clean=1; + } + } +} +else +{ +print "no command line options set\n"; +} + +### Make sure this file is in a libs path or put the absolute path to it +require("/home/cron/AST_SERVER_conf.pl"); # local configuration file + +if (!$DB_port) {$DB_port='3306';} + +use DBI; + +$dbhA = DBI->connect("DBI:mysql:$DB_database:$DB_server:$DB_port", "$DB_user", "$DB_pass") + or die "Couldn't connect to database: " . DBI->errstr; + + +### Grab Server values from the database +$stmtA = "SELECT local_gmt FROM servers where server_ip = '$server_ip';"; +$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; +$sthA->execute or die "executing: $stmtA ", $dbhA->errstr; +@aryA = $sthA->fetchrow_array; +$DBSERVER_GMT = $aryA[0]; +if (length($DBSERVER_GMT)>0) {$SERVER_GMT = $DBSERVER_GMT;} +$sthA->finish(); + +$secX = time(); + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($secX); + $LOCAL_GMT_OFF = $SERVER_GMT; + $LOCAL_GMT_OFF_STD = $SERVER_GMT; + if ($isdst) {$LOCAL_GMT_OFF++;} + +$GMT_now = ($secX - ($LOCAL_GMT_OFF * 3600)); + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($GMT_now); + $mon++; + $year = ($year + 1900); + if ($mon < 10) {$mon = "0$mon";} + if ($mday < 10) {$mday = "0$mday";} + if ($hour < 10) {$hour = "0$hour";} + if ($min < 10) {$min = "0$min";} + if ($sec < 10) {$sec = "0$sec";} + + if ($DB) {print "TIME DEBUG: $LOCAL_GMT_OFF_STD|$LOCAL_GMT_OFF|$isdst| GMT: $hour:$min\n";} + +if ($wipe_hopper_clean) + { + $stmtA = "DELETE from $vicidial_hopper;"; + $affected_rows = $dbhA->do($stmtA); + if ($DB) {print "Hopper Wiped Clean: $affected_rows\n";} + $event_string = "|HOPPER WIPE CLEAN|"; + &event_logger; + + exit; + } +### Delete leads from inactive lists if there are any +$stmtA = "SELECT * FROM vicidial_lists where active='N';"; +if ($DB) {print $stmtA;} +$inactive_lists=''; +$inactive_lists_count=0; +$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; +$sthA->execute or die "executing: $stmtA ", $dbhA->errstr; +$sthArows=$sthA->rows; +while ($sthArows > $inactive_lists_count) + { + @aryA = $sthA->fetchrow_array; + $inactive_list = $aryA[0]; + $inactive_lists .= "'$inactive_list',"; + $inactive_lists_count++; + } +$sthA->finish(); +if ($DB) {print "Inactive Lists: $inactive_lists_count\n";} + +if ($inactive_lists_count > 0) + { + chop($inactive_lists); + $stmtA = "DELETE from $vicidial_hopper where list_id IN($inactive_lists);"; + $affected_rows = $dbhA->do($stmtA); + if ($DB) {print "Inactive List Leads Deleted: $affected_rows |$stmtA|\n";} + $event_string = "|INACTIVE LIST DEL|$affected_rows|"; + &event_logger; + } + +### BEGIN Change CBHOLD status leads to CALLBK if their vicidial_callbacks time has passed +$stmtA = "SELECT count(*) FROM vicidial_callbacks where callback_time <= '$now_date' and status='ACTIVE';"; +$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; +$sthA->execute or die "executing: $stmtA ", $dbhA->errstr; +@aryA = $sthA->fetchrow_array; +$CBHOLD_count = $aryA[0]; + if ($DB) {print "CALLBACK HOLD: $CBHOLD_count|$stmtA|\n";} +$sthA->finish(); + +if ($CBHOLD_count > 0) + { + $update_leads=''; + $cbc=0; + $cba=0; + $stmtA = "SELECT vicidial_callbacks.lead_id,recipient,campaign_id,vicidial_callbacks.list_id,gmt_offset_now FROM vicidial_callbacks,vicidial_list where callback_time <= '$now_date' and vicidial_callbacks.status='ACTIVE' and vicidial_callbacks.lead_id=vicidial_list.lead_id;"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + while ($sthArows > $cbc) + { + @aryA = $sthA->fetchrow_array; + $lead_ids[$cbc] = $aryA[0]; + $recipient = $aryA[1]; + $update_leads .= "'$lead_ids[$cbc]',"; + if ($recipient == 'ANYONE') + { + $CA_lead_id[$cba] = $aryA[0]; + $CA_campaign_id[$cba] = $aryA[2]; + $CA_list_id[$cba] = $aryA[3]; + $CA_gmt_offset_now[$cba] = $aryA[4]; + $cba++; + } + $cbc++; + } + $sthA->finish(); + if ($cbc > 0) + { + chop($update_leads); + + $stmtA = "UPDATE vicidial_list set status='CALLBK', called_since_last_reset='N' where lead_id IN($update_leads);"; + $affected_rows = $dbhA->do($stmtA); + if ($DB) {print "Scheduled Callbacks Activated: $affected_rows\n";} + $event_string = "|CALLBACKS LISTACT|$affected_rows|"; + &event_logger; + + $stmtA = "UPDATE vicidial_callbacks set status='LIVE' where lead_id IN($update_leads);"; + $affected_rows = $dbhA->do($stmtA); + if ($DB) {print "Scheduled Callbacks Activated: $affected_rows\n";} + $event_string = "|CALLBACKS CB ACT |$affected_rows|"; + &event_logger; + + } + ### INSERT ANYONE CALLBACKS INTO HOPPER DIRECTLY ### + if ( ($cba > 0) && ($insert_auto_CB_to_hopper) ) + { + if ($DB) {print "ANYONE Scheduled Callbacks to Insert into hopper: $cba\n";} + $event_string = "|ANYONE CB HOPPER |$cba|"; + &event_logger; + $CAu=0; + foreach(@CA_lead_id) + { + $stmtA = "INSERT INTO $vicidial_hopper SET lead_id='$CA_lead_id[$CAu]',campaign_id='$CA_campaign_id[$CAu]',list_id='$CA_list_id[$CAu]',gmt_offset_now='$CA_gmt_offset_now[$CAu]';"; + $affected_rows = $dbhA->do($stmtA); + if ($DB) {print "ANYONE Scheduled Callback Inserted into hopper: $affected_rows|$CA_lead_id[$CAu]\n";} + $CAu++; + } + } + } +### END Change CBHOLD status leads to CALLBK if their vicidial_callbacks time has passed + + +@campaign_id=@MT; + +if ($CLIcampaign) + { + $stmtA = "SELECT * from vicidial_campaigns where campaign_id='$CLIcampaign'"; + } +else + { + $stmtA = "SELECT * from vicidial_campaigns where active='Y'"; + } +$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; +$sthA->execute or die "executing: $stmtA ", $dbhA->errstr; +$sthArows=$sthA->rows; +$rec_count=0; +while ($sthArows > $rec_count) + { + @aryA = $sthA->fetchrow_array; + $campaign_id[$rec_count] = "$aryA[0]"; + $dial_status_a[$rec_count] = "$aryA[3]"; + $dial_status_b[$rec_count] = "$aryA[4]"; + $dial_status_c[$rec_count] = "$aryA[5]"; + $dial_status_d[$rec_count] = "$aryA[6]"; + $dial_status_e[$rec_count] = "$aryA[7]"; + $lead_order[$rec_count] = "$aryA[8]"; + if (!$CLIlevel) + {$hopper_level[$rec_count] = "$aryA[13]";} + else + {$hopper_level[$rec_count] = "$CLIlevel";} + $local_call_time[$rec_count] = "$aryA[16]"; + $lead_filter_id[$rec_count] = "$aryA[35]"; + $use_internal_dnc[$rec_count] = "$aryA[43]"; + $rec_count++; + } +$sthA->finish(); +if ($DB) {print "CAMPAIGNS TO PROCESSES HOPPER FOR: $rec_count|$#campaign_id\n";} + + +##### LOOP THROUGH EACH CAMPAIGN AND PROCESS THE HOPPER ##### +$i=0; +foreach(@campaign_id) + { + $VCSdialable_leads=0; + $VCScalls_today=0; + $VCSdrops_today=0; + $VCSdrops_today_pct=0; + $vicidial_log = 'vicidial_log'; + + $stmtA = "SELECT dialable_leads from vicidial_campaign_stats where campaign_id='$campaign_id[$i]';"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $rec_count=0; + while ($sthArows > $rec_count) + { + @aryA = $sthA->fetchrow_array; + $VCSdialable_leads = "$aryA[0]"; + $rec_count++; + } + $sthA->finish(); + + $stmtA = "SELECT count(*) from $vicidial_log where campaign_id='$campaign_id[$i]' and call_date > '$VDL_date';"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $rec_count=0; + while ($sthArows > $rec_count) + { + @aryA = $sthA->fetchrow_array; + $VCScalls_today = "$aryA[0]"; + $rec_count++; + } + $sthA->finish(); + if ($VCScalls_today > 0) + { + $stmtA = "SELECT count(*) from $vicidial_log where campaign_id='$campaign_id[$i]' and call_date > '$VDL_date' and status IN('DROP','XDROP');"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $rec_count=0; + while ($sthArows > $rec_count) + { + @aryA = $sthA->fetchrow_array; + $VCSdrops_today = "$aryA[0]"; + if ($VCSdrops_today > 0) + { + $VCSdrops_today_pct = ( ($VCSdrops_today / $VCScalls_today) * 100 ); + $VCSdrops_today_pct = sprintf("%.2f", $VCSdrops_today_pct); + } + $rec_count++; + } + $sthA->finish(); + } + + + + $stmtA = "UPDATE vicidial_campaign_stats SET calls_today='$VCScalls_today',drops_today='$VCSdrops_today',drops_today_pct='$VCSdrops_today_pct' where campaign_id='$campaign_id[$i]';"; + $affected_rows = $dbhA->do($stmtA); + if ($DBX) {print "campaign stats updated: $affected_rows|$VCScalls_today|$VCSdrops_today|$VCSdrops_today_pct|$campaign_id[$i]|\n";} + + ##### BEGIN calculate what gmt_offset_now values are within the allowed local_call_time setting ### + $g=0; + $p='13'; + $GMT_gmt[0] = ''; + $GMT_hour[0] = ''; + $GMT_day[0] = ''; + if ($DBX) {print "\n |GMT-DAY-HOUR| ";} + while ($p > -13) + { + $pzone = ($GMT_now + ($p * 3600)); + ($psec,$pmin,$phour,$pmday,$pmon,$pyear,$pday,$pyday,$pisdst) = localtime($pzone); + $phour=($phour * 100); + $tz = sprintf("%.2f", $p); + $GMT_gmt[$g] = "$tz"; + $GMT_day[$g] = "$pday"; + $GMT_hour[$g] = ($phour + $pmin); + $p = ($p - 0.25); + if ($DBX) {print "|$GMT_gmt[$g]-$GMT_day[$g]-$GMT_hour[$g]|";} + $g++; + } + if ($DBX) {print "\n";} + + $stmtA = "SELECT * FROM vicidial_call_times where call_time_id='$local_call_time[$i]';"; + if ($DBX) {print " |$stmtA|\n";} + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $rec_count=0; + while ($sthArows > $rec_count) + { + @aryA = $sthA->fetchrow_array; + $Gct_default_start = "$aryA[3]"; + $Gct_default_stop = "$aryA[4]"; + $Gct_sunday_start = "$aryA[5]"; + $Gct_sunday_stop = "$aryA[6]"; + $Gct_monday_start = "$aryA[7]"; + $Gct_monday_stop = "$aryA[8]"; + $Gct_tuesday_start = "$aryA[9]"; + $Gct_tuesday_stop = "$aryA[10]"; + $Gct_wednesday_start = "$aryA[11]"; + $Gct_wednesday_stop = "$aryA[12]"; + $Gct_thursday_start = "$aryA[13]"; + $Gct_thursday_stop = "$aryA[14]"; + $Gct_friday_start = "$aryA[15]"; + $Gct_friday_stop = "$aryA[16]"; + $Gct_saturday_start = "$aryA[17]"; + $Gct_saturday_stop = "$aryA[18]"; + $Gct_state_call_times = "$aryA[19]"; + $rec_count++; + } + $sthA->finish(); + + $ct_states = ''; + $ct_state_gmt_SQL = ''; + $del_state_gmt_SQL = ''; + $ct_srs=0; + $b=0; + if (length($Gct_state_call_times)>2) + { + @state_rules = split(/\|/,$Gct_state_call_times); + $ct_srs = ($#state_rules - 2); + } + while($ct_srs >= $b) + { + if (length($state_rules[$b])>1) + { + $stmtA = "SELECT * from vicidial_state_call_times where state_call_time_id='$state_rules[$b]';"; + if ($DBX) {print " |$stmtA|\n";} + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $rec_count=0; + while ($sthArows > $rec_count) + { + @aryA = $sthA->fetchrow_array; + $Gstate_call_time_id = "$aryA[0]"; + $Gstate_call_time_state = "$aryA[1]"; + $Gsct_default_start = "$aryA[4]"; + $Gsct_default_stop = "$aryA[5]"; + $Gsct_sunday_start = "$aryA[6]"; + $Gsct_sunday_stop = "$aryA[7]"; + $Gsct_monday_start = "$aryA[8]"; + $Gsct_monday_stop = "$aryA[9]"; + $Gsct_tuesday_start = "$aryA[10]"; + $Gsct_tuesday_stop = "$aryA[11]"; + $Gsct_wednesday_start = "$aryA[12]"; + $Gsct_wednesday_stop = "$aryA[13]"; + $Gsct_thursday_start = "$aryA[14]"; + $Gsct_thursday_stop = "$aryA[15]"; + $Gsct_friday_start = "$aryA[16]"; + $Gsct_friday_stop = "$aryA[17]"; + $Gsct_saturday_start = "$aryA[18]"; + $Gsct_saturday_stop = "$aryA[19]"; + $ct_states .="'$Gstate_call_time_state',"; + $rec_count++; + } + $sthA->finish(); + + $r=0; + $state_gmt=''; + $del_state_gmt=''; + while($r < $g) + { + if ($GMT_day[$r]==0) #### Sunday local time + { + if (($Gsct_sunday_start==0) and ($Gsct_sunday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gsct_default_start) and ($GMT_hour[$r]<$Gsct_default_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gsct_sunday_start) and ($GMT_hour[$r]<$Gsct_sunday_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==1) #### Monday local time + { + if (($Gsct_monday_start==0) and ($Gsct_monday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gsct_default_start) and ($GMT_hour[$r]<$Gsct_default_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gsct_monday_start) and ($GMT_hour[$r]<$Gsct_monday_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==2) #### Tuesday local time + { + if (($Gsct_tuesday_start==0) and ($Gsct_tuesday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gsct_default_start) and ($GMT_hour[$r]<$Gsct_default_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gsct_tuesday_start) and ($GMT_hour[$r]<$Gsct_tuesday_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==3) #### Wednesday local time + { + if (($Gsct_wednesday_start==0) and ($Gsct_wednesday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gsct_default_start) and ($GMT_hour[$r]<$Gsct_default_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gsct_wednesday_start) and ($GMT_hour[$r]<$Gsct_wednesday_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==4) #### Thursday local time + { + if (($Gsct_thursday_start==0) and ($Gsct_thursday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gsct_default_start) and ($GMT_hour[$r]<$Gsct_default_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gsct_thursday_start) and ($GMT_hour[$r]<$Gsct_thursday_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==5) #### Friday local time + { + if (($Gsct_friday_start==0) and ($Gsct_friday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gsct_default_start) and ($GMT_hour[$r]<$Gsct_default_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gsct_friday_start) and ($GMT_hour[$r]<$Gsct_friday_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==6) #### Saturday local time + { + if (($Gsct_saturday_start==0) and ($Gsct_saturday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gsct_default_start) and ($GMT_hour[$r]<$Gsct_default_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gsct_saturday_start) and ($GMT_hour[$r]<$Gsct_saturday_stop) ) + {$state_gmt.="'$GMT_gmt[$r]',";} + else + {$del_state_gmt.="'$GMT_gmt[$r]',";} + } + } + $r++; + } + $state_gmt = "$state_gmt'99'"; + $del_state_gmt = "$del_state_gmt'99'"; + $ct_state_gmt_SQL .= "or (state='$Gstate_call_time_state' and gmt_offset_now IN($state_gmt)) "; + $del_state_gmt_SQL .= "or (state='$Gstate_call_time_state' and gmt_offset_now IN($del_state_gmt)) "; + } + + $b++; + } + if (length($ct_states)>2) + { + $ct_states =~ s/,$//gi; + $ct_statesSQL = "and state NOT IN($ct_states)"; + } + else + { + $ct_statesSQL = ""; + } + + $r=0; + $default_gmt=''; + $del_default_gmt=''; + while($r < $g) + { + if ($GMT_day[$r]==0) #### Sunday local time + { + if (($Gct_sunday_start==0) and ($Gct_sunday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gct_default_start) and ($GMT_hour[$r]<$Gct_default_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gct_sunday_start) and ($GMT_hour[$r]<$Gct_sunday_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==1) #### Monday local time + { + if (($Gct_monday_start==0) and ($Gct_monday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gct_default_start) and ($GMT_hour[$r]<$Gct_default_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gct_monday_start) and ($GMT_hour[$r]<$Gct_monday_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==2) #### Tuesday local time + { + if (($Gct_tuesday_start==0) and ($Gct_tuesday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gct_default_start) and ($GMT_hour[$r]<$Gct_default_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gct_tuesday_start) and ($GMT_hour[$r]<$Gct_tuesday_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==3) #### Wednesday local time + { + if (($Gct_wednesday_start==0) and ($Gct_wednesday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gct_default_start) and ($GMT_hour[$r]<$Gct_default_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gct_wednesday_start) and ($GMT_hour[$r]<$Gct_wednesday_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==4) #### Thursday local time + { + if (($Gct_thursday_start==0) and ($Gct_thursday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gct_default_start) and ($GMT_hour[$r]<$Gct_default_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gct_thursday_start) and ($GMT_hour[$r]<$Gct_thursday_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==5) #### Friday local time + { + if (($Gct_friday_start==0) and ($Gct_friday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gct_default_start) and ($GMT_hour[$r]<$Gct_default_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gct_friday_start) and ($GMT_hour[$r]<$Gct_friday_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + } + if ($GMT_day[$r]==6) #### Saturday local time + { + if (($Gct_saturday_start==0) and ($Gct_saturday_stop==0)) + { + if ( ($GMT_hour[$r]>=$Gct_default_start) and ($GMT_hour[$r]<$Gct_default_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + else + { + if ( ($GMT_hour[$r]>=$Gct_saturday_start) and ($GMT_hour[$r]<$Gct_saturday_stop) ) + {$default_gmt.="'$GMT_gmt[$r]',";} + else + {$del_default_gmt.="'$GMT_gmt[$r]',";} + } + } + $r++; + } + + $default_gmt = "$default_gmt'99'"; + $del_default_gmt = "$del_default_gmt'99'"; + $all_gmtSQL = "(gmt_offset_now IN($default_gmt) $ct_statesSQL) $ct_state_gmt_SQL"; + $del_gmtSQL = "(gmt_offset_now IN($del_default_gmt) $ct_statesSQL) $del_state_gmt_SQL"; + + ##### END calculate what gmt_offset_now values are within the allowed local_call_time setting ### + + ##### BEGIN lead recycling parsing and prep ### + + $stmtA = "SELECT * from vicidial_lead_recycle where campaign_id='$campaign_id[$i]' and active='Y';"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + @recycle_status=@MT; + @recycle_delay=@MT; + @recycle_maximum=@MT; + @RSQLdate=@MT; + $rec_ct=0; + while ($sthArows > $rec_ct) + { + @aryA = $sthA->fetchrow_array; + $recycle_status[$rec_ct] = "$aryA[2]"; + $recycle_delay[$rec_ct] = "$aryA[3]"; + $recycle_maximum[$rec_ct] = "$aryA[4]"; + $rec_ct++; + } + $sthA->finish(); + + if ($rec_ct > 0) + { + $rc=0; + $recycle_SQL = "( "; + while($rc < $rec_ct) + { + $secX = time(); + $Rtarget = ($secX - $recycle_delay[$rc]); + ($Rsec,$Rmin,$Rhour,$Rmday,$Rmon,$Ryear,$Rwday,$Ryday,$Risdst) = localtime($Rtarget); + $Ryear = ($Ryear + 1900); + $Rmon++; + if ($Rmon < 10) {$Rmon = "0$Rmon";} + if ($Rmday < 10) {$Rmday = "0$Rmday";} + if ($Rhour < 10) {$Rhour = "0$Rhour";} + if ($Rmin < 10) {$Rmin = "0$Rmin";} + if ($Rsec < 10) {$Rsec = "0$Rsec";} + $RSQLdate[$rc] = "$Ryear-$Rmon-$Rmday $Rhour:$Rmin:$Rsec"; + $Y=1; + $recycle_Y = "'Y'"; + while ($Y < $recycle_maximum[$rc]) + { + $recycle_Y .= ",'Y$Y'"; + $Y++; + } + + if ($rc > 0) {$recycle_SQL .= " or ";} + + $recycle_SQL .= "( (called_since_last_reset IN($recycle_Y)) and (status='$recycle_status[$rc]') and (modify_date < \"$RSQLdate[$rc]\") )"; + + if ($DBX) {print "RECYCLE: |$campaign_id[$i]|$recycle_status[$rc]|$recycle_delay[$rc]|$recycle_maximum[$rc]|$RSQLdate[$rc]|\n";} + $rc++; + } + + $recycle_SQL .= " )"; + + if ($DBX) {print "RECYCLE SQL: |$recycle_SQL|\n";} + } + ##### END lead recycling parsing and prep ### + + if ($DB) {print "Starting hopper run for $campaign_id[$i] campaign- GMT: $local_call_time[$i] HOPPER: $hopper_level[$i] \n";} + + ### Delete the DONE leads if there are any + $stmtA = "DELETE from $vicidial_hopper where campaign_id='$campaign_id[$i]' and status IN('DONE');"; + $affected_rows = $dbhA->do($stmtA); + if ($DB) {print " hopper DONE cleared: $affected_rows\n";} + if ($DBX) {print " |$stmtA|\n";} + + ### Delete the leads that are out of GMT time range if there are any + $stmtA = "DELETE from $vicidial_hopper where campaign_id='$campaign_id[$i]' and ($del_gmtSQL);"; + $affected_rows = $dbhA->do($stmtA); + if ($DB) {print " hopper GMT BAD cleared: $affected_rows\n";} + if ($DBX) {print " |$stmtA|\n";} + + ### Find out how many leads are in the hopper from a specific campaign + $hopper_ready_count=0; + $stmtA = "SELECT count(*) from $vicidial_hopper where campaign_id='$campaign_id[$i]' and status='READY';"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $rec_count=0; + while ($sthArows > $rec_count) + { + @aryA = $sthA->fetchrow_array; + $hopper_ready_count = $aryA[0]; + if ($DB) {print " hopper READY count: $hopper_ready_count\n";} + if ($DBX) {print " |$stmtA|\n";} + $rec_count++; + } + $sthA->finish(); + $event_string = "|$campaign_id[$i]|$hopper_level[$i]|$hopper_ready_count|$local_call_time[$i]||"; + &event_logger; + + ##### IF hopper level is below set minimum, then try to add more leads ##### + if ($hopper_ready_count < $hopper_level[$i]) + { + if ($DB) {print " hopper too low ($hopper_ready_count|$hopper_level[$i]) starting hopper dump\n";} + + ### Get list of the lists in the campaign ### + $stmtA = "SELECT list_id FROM vicidial_lists where campaign_id='$campaign_id[$i]' and active='Y';"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $rec_countLISTS=0; + $camp_lists = ''; + while ($sthArows > $rec_countLISTS) + { + @aryA = $sthA->fetchrow_array; + $camp_lists .= "'$aryA[0]',"; + $rec_countLISTS++; + } + $sthA->finish(); + if (length($camp_lists)<3) {$camp_lists="''";} + else {chop($camp_lists);} + + if ($DB) {print " campaign lists count: $rec_countLISTS | $camp_lists\n";} + if ($DBX) {print " |$stmtA|\n";} + + if ( ($lead_filter_id[$i] !~ /NONE/) && (length($lead_filter_id[$i])>0) ) + { + ### Get SQL of lead filter for the campaign ### + $stmtA = "SELECT lead_filter_sql FROM vicidial_lead_filters where lead_filter_id='$lead_filter_id[$i]';"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $rec_count=0; + while ($sthArows > $rec_count) + { + @aryA = $sthA->fetchrow_array; + $lead_filter_sql[$i] = "$aryA[0]"; + $rec_count++; + } + $sthA->finish(); + $lead_filter_sql[$i] =~ s/^and|and$|^or|or$|^ and|and $|^ or|or $//gi; + $lead_filter_sql[$i] = "and $lead_filter_sql[$i]"; + if ($DB) {print " campaign lists count: $rec_countLISTS | $camp_lists\n";} + if ($DB) {print " lead filter $lead_filter_id[$i] defined for $campaign_id[$i]\n";} + if ($DBX) {print " |$lead_filter_sql[$i]|\n";} + } + else + { + $lead_filter_sql[$i] = ''; + if ($DB) {print " no lead filter defined for campaign: $campaign_id[$i]\n";} + if ($DBX) {print " |$lead_filter_id[$i]|\n";} + } + + $stmtA = "SELECT count(*) FROM vicidial_list where called_since_last_reset='N' and status IN('$dial_status_a[$i]','$dial_status_b[$i]','$dial_status_c[$i]','$dial_status_d[$i]','$dial_status_e[$i]') and list_id IN($camp_lists) and ($all_gmtSQL) $lead_filter_sql[$i];"; + if ($DBX) {print " |$stmtA|\n";} + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $rec_count=0; + while ($sthArows > $rec_count) + { + @aryA = $sthA->fetchrow_array; + $campaign_leads_to_call = "$aryA[0]"; + if ($DB) {print " leads to call count: $campaign_leads_to_call\n";} + if ($DBX) {print " |$stmtA|\n";} + $rec_count++; + } + $sthA->finish(); + + if ($lead_order[$i] =~ /DOWN COUNT 2nd NEW|DOWN COUNT 3rd NEW|DOWN COUNT 4th NEW/) + { + $stmtA = "SELECT count(*) FROM vicidial_list where called_since_last_reset='N' and status IN('NEW') and list_id IN($camp_lists) and ($all_gmtSQL) $lead_filter_sql[$i];"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $rec_count=0; + while ($sthArows > $rec_count) + { + @aryA = $sthA->fetchrow_array; + $NEW_campaign_leads_to_call = "$aryA[0]"; + if ($DB) {print " NEW leads to call count: $NEW_campaign_leads_to_call\n";} + if ($DBX) {print " |$stmtA|\n";} + $rec_count++; + } + $sthA->finish(); + } + + ##### IF no NEW leads to be called, error out of this campaign ##### + if ( ($lead_order[$i] =~ /DOWN COUNT 2nd NEW|DOWN COUNT 3rd NEW|DOWN COUNT 4th NEW/) && ($NEW_campaign_leads_to_call > 0) ) {$GOOD=1;} + else + { + if ($DB) {print " ERROR CANNOT ADD ANY NEW LEADS TO HOPPER\n";} + } + + ##### IF no leads to be called, error out of this campaign ##### + if ($campaign_leads_to_call < 1) + { + if ($DB) {print " ERROR CANNOT ADD ANY LEADS TO HOPPER\n";} + if ($VCSdialable_leads > 0) + { + $stmtA = "UPDATE vicidial_campaign_stats SET dialable_leads='0' where campaign_id='$campaign_id[$i]';"; + $affected_rows = $dbhA->do($stmtA); + if ($DBX) {print "CAMPAIGN STATS: $affected_rows|$stmtA|\n";} + } + } + else + { + if ($VCSdialable_leads != $campaign_leads_to_call) + { + $stmtA = "UPDATE vicidial_campaign_stats SET dialable_leads='$campaign_leads_to_call' where campaign_id='$campaign_id[$i]';"; + $affected_rows = $dbhA->do($stmtA); + if ($DBX) {print "CAMPAIGN STATS: $affected_rows|$stmtA|\n";} + } + if ($DB) {print " Getting Leads to add to hopper\n";} + ### grab leads already in hopper so we don't duplicate + $stmtA = "SELECT lead_id FROM $vicidial_hopper where campaign_id='$campaign_id[$i]';"; + if ($DBX) {print " |$stmtA|\n";} + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $lead_id_lists = ''; + $rec_countLISTS=0; + while ($sthArows > $rec_countLISTS) + { + @aryA = $sthA->fetchrow_array; + $lead_id_lists .= "'$aryA[0]',"; + $rec_countLISTS++; + } + $sthA->finish(); + $lead_id_lists .= "'0'"; + $order_stmt=''; + $NEW_count = 0; + $NEW_level = 0; + $OTHER_level = $hopper_level[$i]; + if ($lead_order[$i] eq "DOWN") {$order_stmt = 'order by lead_id asc';} + if ($lead_order[$i] eq "UP") {$order_stmt = 'order by lead_id desc';} + if ($lead_order[$i] eq "UP LAST NAME") {$order_stmt = 'order by last_name desc, lead_id asc';} + if ($lead_order[$i] eq "DOWN LAST NAME") {$order_stmt = 'order by last_name, lead_id asc';} + if ($lead_order[$i] eq "UP PHONE") {$order_stmt = 'order by phone_number desc, lead_id asc';} + if ($lead_order[$i] eq "DOWN PHONE") {$order_stmt = 'order by phone_number, lead_id asc';} + if ($lead_order[$i] eq "UP COUNT") {$order_stmt = 'order by called_count desc, lead_id asc';} + if ($lead_order[$i] eq "DOWN COUNT") {$order_stmt = 'order by called_count, lead_id asc';} + if ($lead_order[$i] eq "DOWN COUNT 2nd NEW") {$NEW_count = 2;} + if ($lead_order[$i] eq "DOWN COUNT 3rd NEW") {$NEW_count = 3;} + if ($lead_order[$i] eq "DOWN COUNT 4th NEW") {$NEW_count = 4;} + + ### BEGIN recycle grab leads ### + if ($rec_ct > 0) + { + if ($DB) {print " looking for RECYCLE leads, maximum of 100\n";} + + $stmtA = "SELECT lead_id,list_id,gmt_offset_now,phone_number,state FROM vicidial_list where $recycle_SQL and list_id IN($camp_lists) and lead_id NOT IN($lead_id_lists) and ($all_gmtSQL) $lead_filter_sql[$i] limit 100;"; + if ($DBX) {print " |$stmtA|\n";} + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + if ($DB) {print " RECYCLE leads to call count: $sthArows\n";} + if ($DBX) {print " |$stmtA|\n";} + $REC_rec_countLEADS=0; + @REC_leads_to_hopper=@MT; + @REC_lists_to_hopper=@MT; + @REC_phone_to_hopper=@MT; + while ($sthArows > $REC_rec_countLEADS) + { + @aryA = $sthA->fetchrow_array; + $REC_leads_to_hopper[$REC_rec_countLEADS] = "$aryA[0]"; + $REC_lists_to_hopper[$REC_rec_countLEADS] = "$aryA[1]"; + $REC_gmt_to_hopper[$REC_rec_countLEADS] = "$aryA[2]"; + $REC_phone_to_hopper[$REC_rec_countLEADS] = "$aryA[3]"; + $REC_state_to_hopper[$REC_rec_countLEADS] = "$aryA[4]"; + if ($DB_show_offset) {print "LEAD_ADD: $aryA[2] $aryA[3] $aryA[4]\n";} + $REC_rec_countLEADS++; + } + $sthA->finish(); + } + ### END recycle grab leads ### + + + + + + + + + if ($NEW_count > 0) + { + $NEW_level = int($hopper_level[$i] / $NEW_count); + $OTHER_level = ($hopper_level[$i] - $NEW_level); + $order_stmt = 'order by called_count, lead_id asc'; + if ($DB) {print " looking for $NEW_level NEW leads mixed in with $OTHER_level other leads\n";} + + $stmtA = "SELECT lead_id,list_id,gmt_offset_now,phone_number,state FROM vicidial_list where called_since_last_reset='N' and status IN('NEW') and list_id IN($camp_lists) and lead_id NOT IN($lead_id_lists) and ($all_gmtSQL) $lead_filter_sql[$i] $order_stmt limit $NEW_level;"; + if ($DBX) {print " |$stmtA|\n";} + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $NEW_rec_countLEADS=0; + @NEW_leads_to_hopper=@MT; + @NEW_lists_to_hopper=@MT; + @NEW_phone_to_hopper=@MT; + while ($sthArows > $NEW_rec_countLEADS) + { + @aryA = $sthA->fetchrow_array; + $NEW_leads_to_hopper[$NEW_rec_countLEADS] = "$aryA[0]"; + $NEW_lists_to_hopper[$NEW_rec_countLEADS] = "$aryA[1]"; + $NEW_gmt_to_hopper[$NEW_rec_countLEADS] = "$aryA[2]"; + $NEW_phone_to_hopper[$NEW_rec_countLEADS] = "$aryA[3]"; + $NEW_state_to_hopper[$NEW_rec_countLEADS] = "$aryA[4]"; + if ($DB_show_offset) {print "LEAD_ADD: $aryA[2] $aryA[3] $aryA[4]\n";} + $NEW_rec_countLEADS++; + } + $sthA->finish(); + } + + if ($DB) {print " lead call order: $order_stmt\n";} + $stmtA = "SELECT lead_id,list_id,gmt_offset_now,phone_number,state FROM vicidial_list where called_since_last_reset='N' and status IN('$dial_status_a[$i]','$dial_status_b[$i]','$dial_status_c[$i]','$dial_status_d[$i]','$dial_status_e[$i]') and list_id IN($camp_lists) and lead_id NOT IN($lead_id_lists) and ($all_gmtSQL) $lead_filter_sql[$i] $order_stmt limit $OTHER_level;"; + if ($DBX) {print " |$stmtA|\n";} + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $rec_countLEADS=0; $NEW_dec=99; $NEW_in=0; + @leads_to_hopper=@MT; + @lists_to_hopper=@MT; + @gmt_to_hopper=@MT; + @state_to_hopper=@MT; + @phone_to_hopper=@MT; + $rec_count=0; + $REC_insert_count=0; + while ($sthArows > $rec_count) + { + @aryA = $sthA->fetchrow_array; + if ( ($NEW_count > 0) && ($NEW_rec_countLEADS > $NEW_in) ) + { + if ($DB_show_offset) {print "NEW_COUNT: $NEW_count|$NEW_dec|$NEW_in|$NEW_rec_countLEADS\n";} + if ($NEW_count > $NEW_dec) + { + $NEW_dec++; + } + else + { + $leads_to_hopper[$rec_countLEADS] = "$NEW_leads_to_hopper[$NEW_in]"; + $lists_to_hopper[$rec_countLEADS] = "$NEW_lists_to_hopper[$NEW_in]"; + $gmt_to_hopper[$rec_countLEADS] = "$NEW_gmt_to_hopper[$NEW_in]"; + $state_to_hopper[$rec_countLEADS] = "$NEW_state_to_hopper[$NEW_in]"; + $phone_to_hopper[$rec_countLEADS] = "$NEW_phone_to_hopper[$NEW_in]"; + if ($DB_show_offset) {print "LEAD_ADD: $NEW_leads_to_hopper[$NEW_in] $NEW_phone_to_hopper[$NEW_in]\n";} + $rec_countLEADS++; + $NEW_in++; + $NEW_dec=2; + } + } + if ($REC_rec_countLEADS > $REC_insert_count) + { + $leads_to_hopper[$rec_countLEADS] = "$REC_leads_to_hopper[$REC_insert_count]"; + $lists_to_hopper[$rec_countLEADS] = "$REC_lists_to_hopper[$REC_insert_count]"; + $gmt_to_hopper[$rec_countLEADS] = "$REC_gmt_to_hopper[$REC_insert_count]"; + $state_to_hopper[$rec_countLEADS] = "$REC_state_to_hopper[$REC_insert_count]"; + $phone_to_hopper[$rec_countLEADS] = "$REC_phone_to_hopper[$REC_insert_count]"; + $rec_countLEADS++; + $REC_insert_count++; + } + $leads_to_hopper[$rec_countLEADS] = "$aryA[0]"; + $lists_to_hopper[$rec_countLEADS] = "$aryA[1]"; + $gmt_to_hopper[$rec_countLEADS] = "$aryA[2]"; + $state_to_hopper[$rec_countLEADS] = "$aryA[4]"; + $phone_to_hopper[$rec_countLEADS] = "$aryA[3]"; + if ($DB_show_offset) {print "LEAD_ADD: $aryA[2] $aryA[3] $aryA[4]\n";} + $rec_countLEADS++; + $rec_count++; + } + $sthA->finish(); + if ($DB) {print " Adding to hopper: $rec_countLEADS\n";} + $event_string = "|$campaign_id[$i]|Added to hopper $rec_countLEADS|"; + &event_logger; + + $h=0; + foreach(@leads_to_hopper) + { + if ($leads_to_hopper[$h] != '0') + { + $DNClead=0; + if ($use_internal_dnc[$i] =~ /Y/) + { + if ($DB) {print " Doinbg DNC Check: $phone_to_hopper[$h] - $use_internal_dnc[$i]\n";} + $stmtA = "SELECT count(*) from vicidial_dnc where phone_number='$phone_to_hopper[$h]';"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $rec_count=0; + while ($sthArows > $rec_count) + { + @aryA = $sthA->fetchrow_array; + $DNClead = "$aryA[0]"; + $rec_count++; + } + $sthA->finish(); + if ($DNClead != '0') + { + $stmtA = "UPDATE vicidial_list SET status='DNCL' where lead_id='$leads_to_hopper[$h]';"; + $affected_rows = $dbhA->do($stmtA); + if ($DBX) {print "Flagging DNC lead: $affected_rows $phone_to_hopper[$h]\n";} + } + } + if ($DNClead == '0') + { + $stmtA = "INSERT INTO $vicidial_hopper (lead_id,campaign_id,status,user,list_id,gmt_offset_now,state) values('$leads_to_hopper[$h]','$campaign_id[$i]','READY','','$lists_to_hopper[$h]','$gmt_to_hopper[$h]','$state_to_hopper[$h]');"; + $affected_rows = $dbhA->do($stmtA); + if ($DBX) {print "LEAD INSERTED: $affected_rows|$leads_to_hopper[$h]|\n";} + } + } + $h++; + } + if ($DB) {print " DONE with this campaign\n";} + + } + } + + + $i++; + } + + +$dbhA->disconnect(); + +if($DB){print "DONE... Exiting... Goodbye... See you later... Really, I mean it :)\n";} + +exit; + + + +sub event_logger { + ### open the log file for writing ### + open(Lout, ">>$VDHLOGfile") + || die "Can't open $VDHLOGfile: $!\n"; + + print Lout "$now_date|$event_string|\n"; + + close(Lout); + +$event_string=''; +} + + diff --git a/DBI-scripts/AST_agent_week.pl b/DBI-scripts/AST_agent_week.pl new file mode 100644 index 00000000..e8eb993a --- /dev/null +++ b/DBI-scripts/AST_agent_week.pl @@ -0,0 +1,336 @@ +#!/usr/bin/perl + +# AST_agent_week.pl +# +# This script is designed to gather stats for all agent activity over the course +# of a week(Sunday to Saturday) and print it in an ASCI text file to be placed +# on a web server for viewing. +# +# CHANGES +# 60517-1100 - First version +# + +$txt = '.txt'; +$US = '_'; +$MT[0] = ''; + +### begin parsing run-time options ### +if (length($ARGV[0])>1) +{ + $i=0; + while ($#ARGV >= $i) + { + $args = "$args $ARGV[$i]"; + $i++; + } + + if ($args =~ /--help/i) + { + print "allowed run time options:\n [-q] = quiet\n [-t] = test\n\n"; + exit; + } + else + { + if ($args =~ /--debug/i) + { + $DB=1; + print "\n-----DEBUG MODE-----\n\n"; + } + if ($args =~ /-q/i) + { + $q=1; $Q=1; + } + if ($args =~ /-t/i) + { + $T=1; $TEST=1; + print "\n-----TESTING-----\n\n"; + } + } +} +else +{ +print "no command line options set\n"; +} +### end parsing run-time options ### + + +$secX = time(); + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); + $year = ($year + 1900); + $mon++; + if ($mon < 10) {$mon = "0$mon";} + if ($mday < 10) {$mday = "0$mday";} + if ($hour < 10) {$hour = "0$hour";} + if ($min < 10) {$min = "0$min";} + if ($sec < 10) {$sec = "0$sec";} + $filedate = "$year$mon$mday-$hour$min$sec"; + $ABIfiledate = "$mon-$mday-$year$us$hour$min$sec"; + $shipdate = "$year-$mon-$mday"; + $datestamp = "$year/$mon/$mday $hour:$min"; + + $STARTtarget = ($secX - (86400 * $wday)); + ($Ssec,$Smin,$Shour,$Smday,$Smon,$Syear,$Swday,$Syday,$Sisdst) = localtime($STARTtarget); + $Syear = ($Syear + 1900); $Smon++; + if ($Smon < 10) {$Smon = "0$Smon";} + if ($Smday < 10) {$Smday = "0$Smday";} + $START_week = (($Syday/7)+1); $START_week = sprintf("%2d", $START_week); + $STARTtarget_date = "$Syear-$Smon-$Smday"; + + $ENDtarget = ($STARTtarget + (86400 * 6)); + ($Ssec,$Smin,$Shour,$Smday,$Smon,$Syear,$Swday,$Syday,$Sisdst) = localtime($ENDtarget); + $Syear = ($Syear + 1900); $Smon++; + if ($Smon < 10) {$Smon = "0$Smon";} + if ($Smday < 10) {$Smday = "0$Smday";} + $ENDtarget_date = "$Syear-$Smon-$Smday"; + + $PAST_STARTtarget = ($STARTtarget - (86400 * 7)); + ($Ssec,$Smin,$Shour,$Smday,$Smon,$Syear,$Swday,$Syday,$Sisdst) = localtime($PAST_STARTtarget); + $Syear = ($Syear + 1900); $Smon++; + if ($Smon < 10) {$Smon = "0$Smon";} + if ($Smday < 10) {$Smday = "0$Smday";} + $PAST_START_week = (($Syday/7)+1); $PAST_START_week = sprintf("%2d", $PAST_START_week); + $PAST_STARTtarget_date = "$Syear-$Smon-$Smday"; + + $PAST_ENDtarget = ($ENDtarget - (86400 * 7)); + ($Ssec,$Smin,$Shour,$Smday,$Smon,$Syear,$Swday,$Syday,$Sisdst) = localtime($PAST_ENDtarget); + $Syear = ($Syear + 1900); $Smon++; + if ($Smon < 10) {$Smon = "0$Smon";} + if ($Smday < 10) {$Smday = "0$Smday";} + $PAST_ENDtarget_date = "$Syear-$Smon-$Smday"; + + $PAST_date[0] = $PAST_STARTtarget_date; + $PAST_day[0] = 'Sunday '; + $PAST_date[6] = $PAST_ENDtarget_date; + $PAST_day[6] = 'Saturday '; + + $PAST_Mondaytarget = ($STARTtarget - (86400 * 6)); + ($Ssec,$Smin,$Shour,$Smday,$Smon,$Syear,$Swday,$Syday,$Sisdst) = localtime($PAST_Mondaytarget); + $Syear = ($Syear + 1900); $Smon++; + if ($Smon < 10) {$Smon = "0$Smon";} + if ($Smday < 10) {$Smday = "0$Smday";} + $PAST_date[1] = "$Syear-$Smon-$Smday"; + $PAST_day[1] = 'Monday '; + + $PAST_Tuesdaytarget = ($STARTtarget - (86400 * 5)); + ($Ssec,$Smin,$Shour,$Smday,$Smon,$Syear,$Swday,$Syday,$Sisdst) = localtime($PAST_Tuesdaytarget); + $Syear = ($Syear + 1900); $Smon++; + if ($Smon < 10) {$Smon = "0$Smon";} + if ($Smday < 10) {$Smday = "0$Smday";} + $PAST_date[2] = "$Syear-$Smon-$Smday"; + $PAST_day[2] = 'Tuesday '; + + $PAST_Wednesdaytarget = ($STARTtarget - (86400 * 4)); + ($Ssec,$Smin,$Shour,$Smday,$Smon,$Syear,$Swday,$Syday,$Sisdst) = localtime($PAST_Wednesdaytarget); + $Syear = ($Syear + 1900); $Smon++; + if ($Smon < 10) {$Smon = "0$Smon";} + if ($Smday < 10) {$Smday = "0$Smday";} + $PAST_date[3] = "$Syear-$Smon-$Smday"; + $PAST_day[3] = 'Wednesday'; + + $PAST_Thursdaytarget = ($STARTtarget - (86400 * 3)); + ($Ssec,$Smin,$Shour,$Smday,$Smon,$Syear,$Swday,$Syday,$Sisdst) = localtime($PAST_Thursdaytarget); + $Syear = ($Syear + 1900); $Smon++; + if ($Smon < 10) {$Smon = "0$Smon";} + if ($Smday < 10) {$Smday = "0$Smday";} + $PAST_date[4] = "$Syear-$Smon-$Smday"; + $PAST_day[4] = 'Thursday '; + + $PAST_Fridaytarget = ($STARTtarget - (86400 * 2)); + ($Ssec,$Smin,$Shour,$Smday,$Smon,$Syear,$Swday,$Syday,$Sisdst) = localtime($PAST_Fridaytarget); + $Syear = ($Syear + 1900); $Smon++; + if ($Smon < 10) {$Smon = "0$Smon";} + if ($Smday < 10) {$Smday = "0$Smday";} + $PAST_date[5] = "$Syear-$Smon-$Smday"; + $PAST_day[5] = 'Friday '; + +print "\n\n\n\n\n\n\n\n\n\n\n\n-- AST_agent_week.pl --\n\n"; +print "This program is designed to print stats to a file for agents' activity for the previous week. \n\n"; + +$TLoutfile = ''; +$TLoutfile .= "TODAY: $shipdate\n"; +$TLoutfile .= "THIS WEEK: week $START_week $STARTtarget_date - $ENDtarget_date\n"; +$TLoutfile .= "LAST WEEK: week $PAST_START_week $PAST_STARTtarget_date - $PAST_ENDtarget_date\n\n"; + +#$h=0; +#foreach(@PAST_date) +#{ +#$TLoutfile .= "$PAST_day[$h] $PAST_date[$h]\n"; +#$h++; +#} + +#print "$TLoutfile"; + + +$outfile = "AGENT_HOURS_$PAST_STARTtarget_date$US$PAST_ENDtarget_date$txt"; + +#$dir = '/usr/local/apache2/htdocs'; +$dir = '/home/www/htdocs'; + +### open the X out file for writing ### +open(out, ">$dir/vicidial/agent_reports/$outfile") + || die "Can't open $outfile: $!\n"; + +### Make sure this file is in a libs path or put the absolute path to it +require("/home/cron/AST_SERVER_conf.pl"); # local configuration file + +if (!$DB_port) {$DB_port='3306';} + +use DBI; + +$dbhA = DBI->connect("DBI:mysql:$DB_database:$DB_server:$DB_port", "$DB_user", "$DB_pass") + or die "Couldn't connect to database: " . DBI->errstr; + +$dbhB = DBI->connect("DBI:mysql:$DB_database:$DB_server:$DB_port", "$DB_user", "$DB_pass") + or die "Couldn't connect to database: " . DBI->errstr; + +#$vicidial_agent_log = 'vicidial_agent_log_archive'; +$vicidial_agent_log = 'vicidial_agent_log'; + +########################################################################### +########### PAST WEEK STAT GATHERING LOOP ################################# +########################################################################### +$h=0; +foreach(@PAST_date) +{ + print out "\n$PAST_day[$h] $PAST_date[$h]\n\n"; + print out "AGENT USER CALLS TALK PAUSE WAIT DISPO ACTIVE LOGTIME FIRST LAST \n"; + print "\n$PAST_day[$h] $PAST_date[$h]\n\n"; + print "AGENT USER CALLS TALK PAUSE WAIT DISPO ACTIVE LOGTIME FIRST LAST \n"; + + $stmtA = "select count(*) as calls, full_name,vicidial_users.user,sum(talk_sec),sum(pause_sec),sum(wait_sec),sum(dispo_sec) from vicidial_users,$vicidial_agent_log where event_time <= '$PAST_date[$h] 23:59:59' and event_time >= '$PAST_date[$h] 00:00:00' and vicidial_users.user=$vicidial_agent_log.user and pause_sec<48800 and wait_sec<48800 and talk_sec<48800 and dispo_sec<48800 group by vicidial_users.user order by full_name limit 10000;"; + $sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr; + $sthA->execute or die "executing: $stmtA ", $dbhA->errstr; + $sthArows=$sthA->rows; + $rec_count=0; + while ($sthArows > $rec_count) + { + @aryA = $sthA->fetchrow_array; + + $calls = sprintf("%7s", $aryA[0]); + $name = sprintf("%-20s", $aryA[1]); while(length($name)>20) {chop($name);} + $user = sprintf("%-8s", $aryA[2]); + + ### TOTAL ACTIVE TIME + $active = ($aryA[3] + $aryA[4] + $aryA[5] + $aryA[6]); + $TIME_S = $active; + $TIME_H = int($TIME_S / 3600); + $TIME_S = ($TIME_S - ($TIME_H * 3600)); + $TIME_M = int($TIME_S / 60); + $TIME_S = ($TIME_S - ($TIME_M * 60)); + if ($TIME_S < 10) {$TIME_S = "0$TIME_S";} + if ($TIME_M < 10) {$TIME_M = "0$TIME_M";} + $TIME_HMS = "$TIME_H:$TIME_M:$TIME_S"; + $active = sprintf("%9s", $TIME_HMS); + + ### TOTAL TALK TIME + $TIME_S = $aryA[3]; + $TIME_H = int($TIME_S / 3600); + $TIME_S = ($TIME_S - ($TIME_H * 3600)); + $TIME_M = int($TIME_S / 60); + $TIME_S = ($TIME_S - ($TIME_M * 60)); + if ($TIME_S < 10) {$TIME_S = "0$TIME_S";} + if ($TIME_M < 10) {$TIME_M = "0$TIME_M";} + $TIME_HMS = "$TIME_H:$TIME_M:$TIME_S"; + $talk = sprintf("%9s", $TIME_HMS); + + ### TOTAL PAUSE TIME + $TIME_S = $aryA[4]; + $TIME_H = int($TIME_S / 3600); + $TIME_S = ($TIME_S - ($TIME_H * 3600)); + $TIME_M = int($TIME_S / 60); + $TIME_S = ($TIME_S - ($TIME_M * 60)); + if ($TIME_S < 10) {$TIME_S = "0$TIME_S";} + if ($TIME_M < 10) {$TIME_M = "0$TIME_M";} + $TIME_HMS = "$TIME_H:$TIME_M:$TIME_S"; + $pause = sprintf("%9s", $TIME_HMS); + + ### TOTAL WAIT TIME + $TIME_S = $aryA[5]; + $TIME_H = int($TIME_S / 3600); + $TIME_S = ($TIME_S - ($TIME_H * 3600)); + $TIME_M = int($TIME_S / 60); + $TIME_S = ($TIME_S - ($TIME_M * 60)); + if ($TIME_S < 10) {$TIME_S = "0$TIME_S";} + if ($TIME_M < 10) {$TIME_M = "0$TIME_M";} + $TIME_HMS = "$TIME_H:$TIME_M:$TIME_S"; + $wait = sprintf("%9s", $TIME_HMS); + + ### TOTAL DISPO TIME + $TIME_S = $aryA[6]; + $TIME_H = int($TIME_S / 3600); + $TIME_S = ($TIME_S - ($TIME_H * 3600)); + $TIME_M = int($TIME_S / 60); + $TIME_S = ($TIME_S - ($TIME_M * 60)); + if ($TIME_S < 10) {$TIME_S = "0$TIME_S";} + if ($TIME_M < 10) {$TIME_M = "0$TIME_M";} + $TIME_HMS = "$TIME_H:$TIME_M:$TIME_S"; + $dispo = sprintf("%9s", $TIME_HMS); + + $stmtB = "select event_time,UNIX_TIMESTAMP(event_time) from $vicidial_agent_log where event_time <= '$PAST_date[$h] 23:59:59' and event_time >= '$PAST_date[$h] 00:00:00' and user='$aryA[2]' order by event_time limit 1;"; + $sthB = $dbhB->prepare($stmtB) or die "preparing: ",$dbhB->errstr; + $sthB->execute or die "executing: $stmtA ", $dbhB->errstr; + @aryB = $sthB->fetchrow_array; + $first_time = sprintf("%21s", $aryB[0]); + $first_log = $aryB[1]; + + $stmtB = "select event_time,UNIX_TIMESTAMP(event_time) from $vicidial_agent_log where event_time <= '$PAST_date[$h] 23:59:59' and event_time >= '$PAST_date[$h] 00:00:00' and user='$aryA[2]' order by event_time desc limit 1;"; + $sthB = $dbhB->prepare($stmtB) or die "preparing: ",$dbhB->errstr; + $sthB->execute or die "executing: $stmtA ", $dbhB->errstr; + @aryB = $sthB->fetchrow_array; + $last_time = sprintf("%21s", $aryB[0]); + $last_log = $aryB[1]; + + $TIME_S = ($last_log - $first_log); + $TIME_H = int($TIME_S / 3600); + $TIME_S = ($TIME_S - ($TIME_H * 3600)); + $TIME_M = int($TIME_S / 60); + $TIME_S = ($TIME_S - ($TIME_M * 60)); + if ($TIME_S < 10) {$TIME_S = "0$TIME_S";} + if ($TIME_M < 10) {$TIME_M = "0$TIME_M";} + $TIME_HMS = "$TIME_H:$TIME_M:$TIME_S"; + $login_time = sprintf("%9s", $TIME_HMS); + + + + print out "$name$user$calls$talk$pause$wait$dispo$active$login_time$first_time$last_time\n"; + print "$name$user$calls$talk$pause$wait$dispo$active$login_time$first_time$last_time\n"; + + + $rec_count++; + } + $sthA->finish(); + + + + + + + + + + +#if ($h=='1') +# { +# exit; +# } + +$h++; +} + + + +close(out); + +### calculate time to run script ### +$secY = time(); +$secZ = ($secY - $secX); +$secZm = ($secZ /60); + +print "script execution time in seconds: $secZ minutes: $secZm\n"; + +exit; + + + + + diff --git a/DTMF_sounds/0.gsm b/DTMF_sounds/0.gsm new file mode 100644 index 0000000000000000000000000000000000000000..8c57c4117ffddedb818b6b0e6b4e15364ce9ea05 GIT binary patch literal 429 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 literal 0 HcmV?d00001 diff --git a/DTMF_sounds/1.gsm b/DTMF_sounds/1.gsm new file mode 100644 index 00000000..7f6c842f --- /dev/null +++ b/DTMF_sounds/1.gsm @@ -0,0 +1 @@ +8z*PScOȪP,r)" +E<7j2h#8誙B,65Cb (Ra.4WFR2) 8z.hK]%Mq]ͷM] %ty\ ,Yc:Sd<,iUK:B.eZ%Vn*䡝QE!t+DC5сWETbok]bcCzՔ.46_M]]Dbv])`]kʜ_uY]UU2Fr.]MtZld]C]6]Y[.jR=_a 뭺_ܭ1Z]r2բ)6A]](,Q]\gS4a&Q2c>v\udI$P`u \ No newline at end of file diff --git a/DTMF_sounds/1.wav b/DTMF_sounds/1.wav new file mode 100644 index 0000000000000000000000000000000000000000..e5f5359a294a5900b1b74f9df930ece805b3e34b GIT binary patch literal 4100 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 +wCY 藡J,FsͮZx<>_"q- ) *Ƭs Psv_cgβrG$R 埗Y \ No newline at end of file diff --git a/DTMF_sounds/2.wav b/DTMF_sounds/2.wav new file mode 100644 index 0000000000000000000000000000000000000000..c3e9edd97f771d36d77ca1a4cd0958b628209a3f GIT binary patch literal 4018 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 K2d#)V-v0w3v(Uo; literal 0 HcmV?d00001 diff --git a/DTMF_sounds/3.gsm b/DTMF_sounds/3.gsm new file mode 100644 index 00000000..a41d6679 --- /dev/null +++ b/DTMF_sounds/3.gsm @@ -0,0 +1,2 @@ +;=PW1W#X [r)d[K%7 +$c#2+)UBV4F¬SC{4[Hnpޥꕷbªσ`gC?=W n(*En,{Q6qR=!Ʈ\b#V) h~R=ѓ \%.kn\R=pzr>ܙ=$u R=ρfGϠȵj&ayC<·+61㍂aϣpK;WClRLJ$=Rf%>##xwb LM}bj&V:3k+[? kS%vAbÝ97qݑ \ No newline at end of file diff --git a/DTMF_sounds/3.wav b/DTMF_sounds/3.wav new file mode 100644 index 0000000000000000000000000000000000000000..bc37ff5d389bdaf8bb4566cfaaba19a938ba7bb1 GIT binary patch literal 4046 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 literal 0 HcmV?d00001 diff --git a/DTMF_sounds/4.gsm b/DTMF_sounds/4.gsm new file mode 100644 index 00000000..d2bae3f8 --- /dev/null +++ b/DTMF_sounds/4.gsm @@ -0,0 +1,2 @@ +8PRW\-elG'XVb,b*V rK"bTJ5~aȋf9ZTȁ`IZ^8nYZ2!Qhzk*"xS8nƸ*"fsSzCdփHΡQTmqZsb=iB +Vbc #meTQJeS;4UQ\H'k JX+ 82U" #9k:'Q "I.Sc"7оRr%ڜD~V΢e Vqr!EKi}9EiUELyXz9#3ȭrQ Ysq[HܘaM2 \ No newline at end of file diff --git a/DTMF_sounds/4.wav b/DTMF_sounds/4.wav new file mode 100644 index 0000000000000000000000000000000000000000..05f1adf82f2799a28bc85b85eee27935ab5975da GIT binary patch literal 3990 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 literal 0 HcmV?d00001 diff --git a/DTMF_sounds/5.gsm b/DTMF_sounds/5.gsm new file mode 100644 index 00000000..239c7aca --- /dev/null +++ b/DTMF_sounds/5.gsm @@ -0,0 +1 @@ +xj=P3cWcT qFܚ$DVD%CHxS&TxD?4A9E'ڸU2r [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 s7#P(MYvO-q6+){VF_1c<2wP#g*NN{r|i761SM literal 0 HcmV?d00001 diff --git a/DTMF_sounds/6.gsm b/DTMF_sounds/6.gsm new file mode 100644 index 00000000..2a25381f --- /dev/null +++ b/DTMF_sounds/6.gsm @@ -0,0 +1 @@ +D;3P2FXLQEFFFyD֟-~ㄧ(;Em3ڵ<\ԬKida1s 5~yjXWQW™䢤V=?4B2%XWjfRyUB]i‰ΝD=':WBax"t )硺,NSWXWlK%a.Ռ̩ح4+Mv_dȗ˱.#IZAY \ No newline at end of file diff --git a/DTMF_sounds/6.wav b/DTMF_sounds/6.wav new file mode 100644 index 0000000000000000000000000000000000000000..7c32ca3622960600b4a58cd647f297a98a22a74a GIT binary patch literal 4046 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 literal 0 HcmV?d00001 diff --git a/DTMF_sounds/7.gsm b/DTMF_sounds/7.gsm new file mode 100644 index 00000000..0260531d --- /dev/null +++ b/DTMF_sounds/7.gsm @@ -0,0 +1,2 @@ +8PR=:^ +r(۞fM[E88vG(QE!f݅ Q[O*֩r<HWSwt8Dx"IGDL4:RīUXj]H䋨L~rA fa֮2_(9FܗL]ëRQh_7#uGB.Vi]McjE2[vADyac]loHtRFz􇁗Hy!Aq8!QȤc=6 B)SdޭU9"<55c=ۉmbSc_ܩHUD{7=_!1֥!S왩n:5P!ku \ No newline at end of file diff --git a/DTMF_sounds/7.wav b/DTMF_sounds/7.wav new file mode 100644 index 0000000000000000000000000000000000000000..6cdce5c18b06074dd3b0a8261c857002298e3a5a GIT binary patch literal 4072 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 XJKve|ofrfSA+R6T_(p5}Ih_9o9Fpc= literal 0 HcmV?d00001 diff --git a/DTMF_sounds/8.gsm b/DTMF_sounds/8.gsm new file mode 100644 index 0000000000000000000000000000000000000000..e931896ab9637a44a609d6c40288acf63742874d GIT binary patch literal 429 zcmV;e0aE_ecw=`xP%`mW9Mw)<4T~d@xZJ2Di429(vEoEzWD*xc)p%3?JcVN;T98DR z%|jO%#Yj3~f-MDYVIqaW^qn=j&eeE&_dQ`@!&x;d#hW5P=~YNnzaga}NBI=JWLDGeya_c=V)zx@< z_dMg_i5St&VqxHe+O43yP)TfaT4VXE=Mh)O7Ga^> zGLjtJse$DOD$%0Vcuccel&OPw<8C)&)p%RF^6{fZ zF__L@g`z&4hQ#@W;#N9RykcJ>wz;w%Y}I&Me>~0NDa5UG?(rfY2cqF=so}P}S`7u| z;+qAAQ!3SXV|zS>0nwV2ROIDh)f_d)N8@3ru&y4Wse#ue6}3gxw92M^VTUBK&Ymk_ X$DTE77g=$vWfnC>dsM88B$3G+CN0|n literal 0 HcmV?d00001 diff --git a/DTMF_sounds/8.wav b/DTMF_sounds/8.wav new file mode 100644 index 0000000000000000000000000000000000000000..3ed04b3b11351fd161c39e8a4390f79746826e1e GIT binary patch literal 4018 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 X>`0?>I5fHd-L3Zfc3dF6ZMNI4W0~m? literal 0 HcmV?d00001 diff --git a/DTMF_sounds/9.wav b/DTMF_sounds/9.wav new file mode 100644 index 0000000000000000000000000000000000000000..1439a5954012827576236c3e07e7f2273bc4c8d1 GIT binary patch literal 4018 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�dW<)$nv!YX^a+JVs`^H1R%P$U5Ut&SQrKBtu2i_NIWx*x5|dLn5J-bNlL$ zS(4x$zOZ?o&IQi1`E()lqmgoeX0_SQ*PEg_s&KR5PQqX?q1OlCb^5j3)CjTbk(4_3 zGiLbd-89}FNFdHYa|P={!qf@yI$P8NBY_tNnN+_G;= z<3WphhKvhO)0074Q8=R;hjYX=@rbB9TLbo$6MAu_{Hs_Q^v{n9PBNC-*)tTOC`BGcLyzRd zjyrL6R!+`%eHeuaeT#k-%G6f|@hzW)`@a*62JqzJcdUBcHX9}GurVDtv)!?+Xu