def patch_caller_as_DIET(caller, keyWordStr, keyWordTable, sessionID):
    """called by handle_staff_caller().
    pretend the caller to be for DIET.
    patch its organization to add a DIET flag.
    somewhat modeled after: get_active_broadcast_item().
    returns the patched caller.
    """

    keyWords = keyWordTable.objects.filter(key_word=keyWordStr)
    if keyWords:
        dsh_utils.db_print(
            'patch_caller_as_DIET: found keyword: '+ \
            repr(keyWords), 136)
        keyWord = keyWords[0]
    else:
        message = 'dsh_common_test.patch_caller_as_DIET: ' + \
                  'failed to locate this key word: ' + keyWordStr
        dsh_utils.give_bad_news(message, logging.error)
        dsh_agi.report_event(message, reportLevel='ERR',
                             sessionID=sessionID)
        return None

    caller.organization.org_key_word = keyWord
    dsh_utils.db_print('patch_caller_as_DIET: caller patched!', 136)
    return caller
def say_digits(number):
    """
    10/04/09: called by read_back_caller_number().
    says the phone numbers
    """

    dsh_common_db.init_log(quiet=True)
    funcName = 'dsh_common_agi.say_digits:'
    number = number.strip()

    soundDir = dsh_common_config.lookup('DSH_PROMPT_DIR')
    sorrySound = dsh_config.lookup('DSH_PROMPT_SORRY')
    sorrySound = os.path.join(soundDir, sorrySound)
    
    if not number:
        dsh_agi.say_it(sorrySound)
        return

    try:
        inumber = int(number)
    except:
        message = '%s not a number: %s.' % (funcName, number)
        dsh_agi.report_event(message, reportLevel='ERR')
        dsh_utils.give_bad_news(message, logging.error)
        dsh_agi.say_it(sorrySound)
        return

    datesDir = os.path.join(soundDir, 'dates')
    dateDir = os.path.join(datesDir, 'dates')

    for digit in number:
        digit = '0' + digit
        sound = os.path.join(dateDir, digit)
        dsh_agi.say_it(sound)
Esempio n. 3
0
def main():
    global globals4signal

    globals4signal["session_id"] = dvoice.db.models.assign_dsh_uid()

    dsh_django2.init_log("dsh_failed: entered, session %s --------------------" % (get_session(),))

    #
    # get the AGI environment variables.
    # chicken out if it's not due to .call failure.
    #
    env = dsh_agi.read_env()
    if env == {}:
        message = "dsh_failed: failed to read agi envs."
        dsh_utils.give_bad_news(message, logging.error)
        dsh_agi.report_event(message, reportLevel="ERR", sessionID=get_session())
        sys.exit(1)

    if not env.has_key("agi_channel"):
        message = "dsh_failed: no agi_channel."
        dsh_utils.give_bad_news(message, logging.error)
        dsh_agi.report_event(message, reportLevel="ERR", sessionID=get_session())
        sys.exit(1)

    if env["agi_channel"] != "OutgoingSpoolFailed":
        message = "dsh_failed: unexpected agi_channel: " + env["agi_channel"]
        dsh_utils.give_bad_news(message, logging.error)
        dsh_agi.report_event(message, reportLevel="ERR", sessionID=get_session())
        sys.exit(1)

    dsh_config.init(env)

    #
    # get the dsh_uid of the callee from the command argument.
    #
    dsh_utils.db_print("dsh_failed: arguments are: " + repr(sys.argv), 116)
    if len(sys.argv) < 2:
        message = "dsh_failed: not enough arguments."
        dsh_utils.give_bad_news(message, logging.error)
        dsh_agi.report_event(message, reportLevel="ERR", sessionID=get_session())
        sys.exit(1)

    calleeDshUid = sys.argv[1].strip()
    if not calleeDshUid:
        message = "dsh_failed: no dshUid found."
        dsh_utils.give_bad_news(message, logging.error)
        dsh_agi.report_event(message, reportLevel="ERR", sessionID=get_session())
        sys.exit(1)

    dsh_utils.db_print("dsh_failed: calleeDshUid: " + calleeDshUid, 116)
    globals4signal["callee_dsh_uid"] = calleeDshUid

    #
    # let's sever ties with Asterisk.
    # this ensures the old .call file is deleted.
    #
    signal.signal(signal.SIGHUP, hangup_signal_handler)
    dsh_agi.send_command("HANGUP\n", caller="dsh_failed:")

    sys.exit(0)
def select_starred():
    """called by views.select_starred()."""

    response = ''

    starred = dv2.db.models.Item.objects.filter(starred=True)
    if not starred:
        response += dsh_utils.red_error_break_msg(
            'no starred item.')
        return response

    count = 0
    for item in starred:
        if item.u17:
            continue
        item.u17 = True

        try:
            item.save(noLogging=True)
            count += 1
        except:
            message = 'dsh_selection.select_starred: failed to save: ' +\
                      item.dsh_uid
            dsh_django_utils.error_event(message, errorLevel='CRT')
            response += dsh_utils.red_error_break_msg(message)
            return response

    message = '%s starred item(s) selected.' % (str(count),)
    response += dsh_utils.black_break_msg(message)
    dsh_agi.report_event(message)

    return response
def auto_dial_disable(request):
    """10/03/19: moved from view.py"""

    if dsh_django_request.deny_it(request):
        return views.please_log_in()

    response = views.page_header('disable auto-dial')

    dsh_db_config.set('auto_dial_disable', True)
    disabled = dsh_db_config.get('auto_dial_disable')
    
    if not disabled:
        message = 'views.auto_dial_disable: unexpected error.'
        response += dsh_utils.red_error_break_msg(message)
        dsh_django_utils.error_event(message, errorLevel='CRT')
        response += views.page_footer()
        return HttpResponse(response)

    response += spool_wipe_status_message()
    dsh_django_utils.auto_schedule_delete_all()

    response += dsh_utils.black_break_msg(
        'now <font color=red><b>disabled</b></font>. ' +\
        'wanna <a href="/autodialenable">re-enable</a>?')
    
    response += views.page_footer()

    dsh_agi.report_event('auto-dial disabled.')

    return HttpResponse(response)
def init_unknown_org_person():
    """if the database doesn't have a default unknown organization, make one.
    if the database doesn't have a default unknown person (for no number),
    make one."""

    #
    # see if we could find the unknown org.  if not, make one.
    #
    unknownOrgAlias = dsh_config.lookup('UNKNOWN_ORG_ALIAS')
    unknownOrgs = Organization.objects.filter(alias=unknownOrgAlias)
    if unknownOrgs:
        unknownOrg = unknownOrgs.latest()
        if len(unknownOrgs) > 1:
            message = 'dsh_django1.init_unknown_org_person: ' + \
                      'more than one unknown org found.'
            dsh_utils.give_news(message, logging.warning)
            dsh_agi.report_event(message, reportLevel='WRN')
        dsh_utils.db_print('dsh_django1: found existing unknown org.', 99)
    else:
        unknownOrg = Organization(
            name='Unknown Organization',
            alias=unknownOrgAlias,
            language='OTH',
            description="""This is a place holder organization for unknown callers, automatically added by Asterisk.""")
        unknownOrg.save()
        dsh_utils.db_print('dsh_django1: created new unknown org.', 99)

    dsh_utils.db_print('dsh_django1: unknownOrg: ' + repr(unknownOrg), 99)

    #
    # see if we could find the unknown person.  if not, make one.
    #
    unknownNumber = dsh_config.lookup('UNKNOWN_PHONE_NUMBER')
    unknownPersonName = dsh_config.lookup('UNKNOWN_PERSON_NAME')
    unknownPersons = Person.objects.filter(
        first_name=unknownPersonName, phone_number=unknownNumber)
    if unknownPersons:
        unknownPerson = unknownPersons.latest()
        if len(unknownPersons) > 1:
            message = 'dsh_django1.init_unknown_org_person: ' + \
                      'more than one unknown person found.'
            dsh_utils.give_news(message, logging.warning)
            dsh_agi.report_event(message, reportLevel='WRN',
                                 phone_number=unknownPerson.phone_number)
        dsh_utils.db_print('dsh_django1: found existing unknown person.', 99)
    else:
        unknownPerson = Person(
            first_name=unknownPersonName,
            phone_number=unknownNumber,
            organization=unknownOrg,
            ptype='OTH',
            gender='F',
            description="""This is the place-holder person for callers whose phone numbers we don't know, automatically added by Asterisk.""")
        unknownPerson.save()
        dsh_utils.db_print('dsh_django1: created new unknown person.', 99)

    dsh_utils.db_print('dsh_django1: unknownPerson: ' + repr(unknownPerson),
                       99)

    return (unknownOrg,unknownPerson)
def check_personalized_followup_to(caller, msg, sessionID,
                                   sayPersonNameFunc=None):
    """
    called by dsh_django2.check_personalized_messages().
    if the followup_to field of the personalized message points
    to caller himself, we want to play the original question
    that resulted in this personalized message.
    modeled after check_personalized_messages().
    sayPersonNameFunc is dsh_django2.say_message_from_name().
    """

    dsh_utils.db_print('check_personalized_followup_to: entered.', 151)
    if not msg or not caller or not msg.owner:
        dsh_utils.db_print('check_personalized_followup_to: nulls.', 151)
        return
    
    question = msg.followup_to
    if not question:
        dsh_utils.db_print('check_personalized_followup_to: no followup_to.',
                           151)
        return

    if question.owner.dsh_uid != caller.dsh_uid:
        #dsh_utils.db_print('check_personalized_followup_to: not same owner.',
        #                   151)
        #return
        pass

    if question.owner.ptype != 'USR':
        #
        # we will read the question back ONLY if the question
        # was left by a "user."
        #
        dsh_utils.db_print('check_personalized_followup_to: '+\
                           'question not by user type.', 151)
        return

    chopped = get_sln_path_for_asterisk(question)
    if not chopped:
        message = 'dsh_common_agi.check_personalized_followup_to: ' +\
                  'unable to find .sln file: ' + repr(question)
        dsh_agi.report_event(message, reportLevel='ERR', sessionID=sessionID)
        dsh_utils.give_bad_news(message, logging.error)
        return

    say_date(question)

    if sayPersonNameFunc:
        dsh_utils.db_print('check_personalized_followup_to: saying name.', 151)
        sayPersonNameFunc(question.owner)

    dsh_agi.say_it(chopped)
    dsh_agi.say_it('beep')
Esempio n. 8
0
def log_event(totals, logAction='STT2', textLog=False):
    """
    puts the stats in the event table.
    """

    message = ('calls: %s, recorded: %s, items: %s, callsnorec: %s, ' +\
               'starred: %s, recdur: %s, calldur: %s') % \
               (str(totals[0]), str(totals[1]), str(totals[2]), str(totals[3]),
                str(totals[4]), str(totals[5]), str(totals[6]))
    dsh_agi.report_event(message, action=logAction)
    if textLog:
        dsh_utils.give_news(message, logging.info)
def chop_prefix_digits_for_local(callNum, callee):
    """
    10/02/02: chopping of the leading zero is moved from
    dsh_django_utils.generate_dot_call_file().
    also adding code to remove 0522.
    """

    dsh_common_db.init_log(quiet=True)

    #if callee.phone_std:
        #
        # 10/03/13:
        # dial as is.
        #
        #return callNum

    dsh_utils.db_print(
        'chop_prefix_digits_for_local: enter: callNum: ' + callNum, 152)
    if len(callNum) > 1 and (not callee.phone_std) and \
       (not callee.phone_landline) and callNum[0] == '0' and \
       (callNum[1] == '9' or callNum[1] == '8'):
        #
        # it looks like Asterisk doesn't like the leading 0
        # for cell phone numbers, chop it off.
        # 10/03/14:
        # now dealing with phone numbers that start with 8.
        #
        callNum = callNum[1:]
        dsh_utils.db_print(
            'chop_prefix_digits_for_local: return1: callNum: ' + callNum, 152)
        return callNum

    localLandLinePrefix = dsh_db_config.get('local_land_line_prefix')
    if not localLandLinePrefix:
        message = 'chop_prefix_digits_for_local: no local land line prefix.'
        dsh_utils.give_bad_news(message, logging.warning)
        dsh_agi.report_event(message, reportLevel='WRN')
        #
        # try_remove_prefix() will deal with null prefix
        # so no need to worry about anything else than logging message.

    #
    # 10/03/14:
    # should look at the callee.phone_landline flag.
    # but I'm not: it's still legit to look for 0522 and kill it
    # even if it was not explicitly marked as a landline.
    #
    callNum = try_remove_prefix(callNum, localLandLinePrefix)

    dsh_utils.db_print(
        'chop_prefix_digits_for_local: returned ' + callNum, 152)
    return callNum
def select_current_dial_set(personTable, action='set'):
    """
    10/03/22.
    called by dsh_common_views.select_current_dial_set().
    add/remove the people in the current dial set to/from
    the current selection.
    basically copied from process_selected_people_current_dial().
    """
    
    response = ''

    people = personTable.objects.filter(current_dial=True)

    count = 0
    for person in people:
        if action == 'set':
            if person.u17:
                continue
            person.u17 = True
        elif action == 'clear':
            if not person.u17:
                continue
            person.u17 = False
        else:
            break

        try:
            person.save(noLogging=True)
            count += 1
        except:
            message = 'dsh_common_selection.' +\
                      'select_current_dial_set: ' +\
                      'failed to save person: ' + person.dsh_uid
            dsh_django_utils.error_event(message, item=person,
                                         errorLevel='CRT')
            response += dsh_utils.red_error_break_msg(message)
            return response

    if action == 'set':
        message = 'People added to the current selection: '
    elif action == 'clear':
        message = 'People removed from the current selection: '
    else:
        message = ''

    if message:
        message += str(count) + '.'

    response += dsh_utils.black_break_msg(message)
    dsh_agi.report_event(message)

    return response
def reschedule_current_dial_set(personTable,
                                tinyResponse=False,
                                sessionID=None):
    """
    10/03/22.
    called by dsh_common_views.reschedule().
    and dsh_reschedule.py
    tinyResponse==True when called by dsh_reschedule.py.
    it just returns the number of people scheduled in that case.
    """

    response = ''

    people = personTable.objects.filter(current_dial=True)

    if not people:
        response += dsh_utils.black_break_msg(
            'No person in the current dial set.')
        if tinyResponse:
            return 0
        return response

    dsh_utils.black_break_msg('Processing the following people...')

    count = 0
    for person in people:
        calleeInfo = '<span style="white-space: nowrap;">' +\
                     dsh_django_utils.callee_info(person) + '</span>'
        response += dsh_utils.black_break_msg(calleeInfo)
        scheduled,strMsg = dsh_django_utils.check_auto_timed_calls_for_person(
            person, noLogging=True)
        if scheduled:
            strMsg = '&nbsp;&nbsp;&nbsp;&nbsp; scheduled: ' + strMsg
        else:
            strMsg = '&nbsp;&nbsp;&nbsp;&nbsp; not scheduled: ' + strMsg
        response += dsh_utils.black_break_msg(strMsg)
        count += 1

    countMsg = dsh_utils.black_break_msg(
        'number of people in the dial set processed: ' +\
        str(count) + '.')
    response += countMsg
    dsh_agi.report_event(countMsg, sessionID=sessionID)

    if tinyResponse:
        return count
    return response
Esempio n. 12
0
def determine_recorded_file_name(caller, outgoingItem):
    #
    # I need to make a new item because that's where the new dsh_uid is.
    #
    item = Item(
        owner=caller,
        itype='I',
        followup_to=outgoingItem)

    #
    # the name has to be computed for placing in the django database.
    # so it's not done lightly.
    #
    incomingFullName = dsh_agi.make_full_unique_filename(
        item.dsh_uid,
        '',
        phoneNumber=caller.phone_number,
        orgAlias=caller.organization.alias,
        name=caller.__unicode__(),
        startWithRoot=True,
        uploadType='asterisk')

    dirName = os.path.dirname(incomingFullName)
    if not dsh_utils.try_mkdir_ifdoesnt_exist(
        dirName, 'dsh_django1.determine_recorded_file_name: '):
        message = 'dsh_django1.dsh_utils.try_mkdir_ifdoesnt_exist failed: '+\
                  dirName
        dsh_utils.give_bad_news(message, logging.critical)
        dsh_agi.report_event(message, reportLevel='CRT')
        return (item, None)

    dsh_utils.chmod_tree2(dirName, recurse=False)

    slnDir = os.path.join(dirName, 'sln')
    if not dsh_utils.try_mkdir_ifdoesnt_exist(
        slnDir, 'dsh_django1.determine_recorded_file_name: '):
        message = 'dsh_django1.dsh_utils.try_mkdir_ifdoesnt_exist failed: '+\
                  'on slnDir: ' + slnDir
        dsh_utils.give_bad_news(message, logging.critical)
        dsh_agi.report_event(message, reportLevel='CRT')
        return (item, None)
    dsh_utils.chmod_tree2(slnDir, recurse=False)
    
    return (item,incomingFullName)
def star(action='add'):
    """star the selection."""

    response = ''
    
    selectedItems = dv2.db.models.Item.objects.filter(u17=True)
    if not selectedItems:
        response += dsh_utils.red_error_break_msg(
            'no item selected currently.')
        return response

    count = 0
    for item in selectedItems:

        if action == 'add':
            if item.starred:
                continue
            item.starred = True
        else:
            if not item.starred:
                continue
            item.starred = False

        try:
            item.save(noLogging=True)
            count += 1
        except:
            message = 'dsh_selection.star: failed to save: ' +\
                      item.dsh_uid
            dsh_django_utils.error_event(message, errorLevel='CRT')
            response += dsh_utils.red_error_break_msg(message)
            return response

    if action == 'add':
        actDone = 'starred'
    else:
        actDone = 'de-starred'
        

    message = '%s item(s) %s.' % (str(count), actDone)
    response += dsh_utils.black_break_msg(message)
    dsh_agi.report_event(message, action='STAR')

    return response
def remove_from_current_dial_if_no_message(
    caller, itemTable, keyWordTable, eventTable,
    noLogging=False, sessionID=''):
    """
    called by somewhere from the signal handler in dsh_django2.py.
    see note100331.
    """
    
    dsh_common_db.init_log(quiet=True)

    if not caller.current_dial:
        dsh_utils.db_print('remove_from_current_dial_if_no_message: ' +\
                           'not in CDS.', 165)
        return
    
    hasMessage,whatStr = person_has_any_message_at_all(
        caller, itemTable, keyWordTable, eventTable,
        noLogging=noLogging, sessionID=sessionID)

    if hasMessage:
        dsh_utils.db_print('remove_from_current_dial_if_no_message: ' +\
                           'has messages: ' + whatStr, 165)
        return

    caller.current_dial = False

    try:
        caller.save(noLogging=noLogging)
    except:
        message = 'dsh_common_agi.remove_from_current_dial_if_no_message: ' +\
                  'failed to save person: ' + caller.dsh_uid
        dsh_django_utils.error_event(message, item=person, errorLevel='CRT')
        dsh_utils.give_bad_news(message, reportLevel='CRT')
        return

    message = 'dsh_common_agi.remove_from_current_dial_if_no_message: ' +\
              'removed from current dial: ' + caller.__unicode__()
    dsh_agi.report_event(
        message,
        action='RCDS',
        owner=caller,
        sessionID=sessionID)
    dsh_utils.give_news(message, logging.info)
def reschedule(request, personTable):
    """
    10/03/19: moved from views.py
    a combination of delete all and active."""
    
    if dsh_django_request.deny_it(request):
        return views.please_log_in()
    
    response = views.page_header('reschedule auto-dialed calls')
    dsh_common_agi.auto_schedule_delete_all()

    response += spool_wipe_status_message()

    disabled = dsh_db_config.get('auto_dial_disable')
    if disabled:
        response += dsh_utils.black_break_msg(
            'global auto-dial is currently ' +\
            '<font color=red><b>disabled</b></font>.')
        response += dsh_utils.black_break_msg(
            'processing people in the current dial set...')
        response += dsh_common_selection.reschedule_current_dial_set(
            personTable)
    else:
        response += dsh_utils.black_break_msg(
            'global auto-dial is currently ' +\
            '<font color=green><b>enabled</b></font>.')
        response += dsh_utils.black_break_msg(
            'processing all people...')
        dsh_django_utils.check_auto_timed_calls_for_all_persons(noLogging=True)

    response += dsh_utils.black_break_msg('done.')
    response += dsh_utils.black_break_msg(
        'see the <a href=/scheduled>schedule</a>.')

    response += views.page_footer()

    dsh_agi.report_event(
        'reschedule triggered by web interface.',
        action='RESC')
    
    return HttpResponse(response)
def field_to_sln_path(field, sessionID=None):
    """
    moved from dsh_django2.py
     fix up the file name: from the database, it's an mp3 URL.
     django should have taken the trouble of converting it to sln alredy.
     we call some function to get the path name of the sln file.
    """
    
    #mp3FilePath = item.file.url
    mp3FilePath = field.url
    pathStuff = dsh_agi.figure_out_sln_names(mp3FilePath)
    if not pathStuff:
        message = 'dsh_django1.get_sln_path_for_asterisk: ' + \
                  'failed to find path stuff for: ' + repr(mp3FilePath)
        dsh_agi.report_event(message, reportLevel='CRT',
                             sessionID=sessionID)
        dsh_utils.give_bad_news(message, logging.critical)
        return None
    slnDir,slnBaseName,wavBaseName,fullSlnName,fullWavName = pathStuff
    dsh_utils.db_print('dsh_django1.get_sln_path_for_asterisk: ' +
                       fullSlnName, 97)

    #
    # do a sanity check of the .sln file.
    #
    if not dsh_utils.is_valid_file(fullSlnName, msg='', silent=True):
        message = 'dsh_django.get_sln_path_for_asterisk: ' + \
                  'not a valid file: ' + fullSlnName
        dsh_agi.report_event(message, reportLevel='ERR',
                             sessionID=sessionID)
        dsh_utils.give_bad_news(message, logging.error)
        return None
    
    #
    # Asterisk doesn't like to be told the .sln extension so get rid of it.
    #
    chopped = fullSlnName.replace('.sln', '')
    dsh_utils.db_print('dsh_django1.get_sln_path_for_asterisk: success: ' +
                       chopped, 108)
    return chopped
Esempio n. 17
0
def get_outgoing_voice_from_db():
    #
    # look up in the django database.
    # look for items that are "active" and are of the "broadcast" type.
    #
    activeBroadcastItems = Item.objects.filter(active=True, itype='B')
    if not activeBroadcastItems:
        message = 'dsh_django1.get_outgoing_voice_from_db: ' + \
                  'no currently active broadcast message.'
        dsh_agi.report_event(message, reportLevel='ERR')
        dsh_utils.give_bad_news(message, logging.error)
        return None
    
    item = activeBroadcastItems[0]
    dsh_utils.db_print('dsh_django1.get_outgoing_voice_from_db: ' +
                       repr(item), 97)

    chopped = get_sln_path_for_asterisk(item)
    if chopped == None:
        return None
        
    return (item,chopped)
Esempio n. 18
0
def determine_unknown_caller(unknownOrg, unknownPerson,
                             phoneNumberLookupResult):
    """if the caller's phone number is not known at all, we say the caller is
    unknownPerson from the unknownOrg.
    if the caller's phone number is known but not in the database,
    we add the caller to the database, and make her belong to unknownOrg."""

    if not phoneNumberLookupResult:
        #
        # we don't know the guy's phone number.
        #
        return unknownPerson

    person,phoneNumber = phoneNumberLookupResult

    if person:
        return person

    #
    # we have a phone number. but the person is not in the database.
    # we should put the person in.
    #
    unknownPersonName = dsh_config.lookup('UNKNOWN_PERSON_NAME')
    newUnknownPerson = Person(
        first_name=unknownPersonName,
        phone_number=phoneNumber,
        organization=unknownOrg,
        ptype='OTH',
        gender='F',
        description="""This unknown caller was automatically added by Asterisk.""")
    newUnknownPerson.save()
    message = 'dsh_django1.determine_caller: ' + \
              'added unknown caller to database with number: ' + \
              phoneNumber
    dsh_utils.give_news(message, logging.info)
    dsh_agi.report_event(message, reportLevel='INF',
                         phone_number=phoneNumber)
    return newUnknownPerson
Esempio n. 19
0
def hangup_signal_handler(signum, frame):
    """called after the hangup signal is received."""

    global globals4signal
    
    dsh_utils.db_print2('dsh_failed.signal_handler: entered...', 116)
    time.sleep(1)
    
    calleeDshUid = globals4signal['callee_dsh_uid']

    if is_triggered_by_dial_now(calleeDshUid):
        sys.exit(0)
    
    callee = dsh_django_utils.get_foreign_key(Person, calleeDshUid)
    if not callee:
        message = 'dsh_failed: no such callee found: ' + calleeDshUid
        dsh_utils.give_bad_news(message, logging.error)
        dsh_agi.report_event(message, reportLevel = 'ERR',
                             sessionID=get_session())
        sys.exit(1)
    else:
        dsh_utils.db_print('dsh_failed: found callee: ' + repr(callee), 116)

    event = Event(
        owner=callee,
        phone_number=callee.phone_number,
        action='NOPU',
        etype='INF',
        description='.call not picked up. re-arming.',
        session=get_session())
    event.save()
    dsh_django_utils.check_auto_timed_calls_for_person(
        callee, sessionID=get_session())

    calleeInfo = dsh_django_utils.callee_info(callee)    
    
    dsh_utils.give_news('dsh_failed.signal_handler: rearming callee: '+\
                        calleeInfo, logging.info)
def reschedule_script_call(personTable):
    """
    10/03/22:
    called by dsh_reschedule.py
    which is in turn invoked by crontab
    """

    sessionID = dsh_common_db.make_session_id()
    dsh_common_agi.auto_schedule_delete_all(sessionID=sessionID)

    disabled = dsh_db_config.get('auto_dial_disable')
    if disabled:
        count = reschedule_current_dial_set(
            personTable, tinyResponse=True, sessionID=sessionID)
        message = 'dsh_reschedule.py: processing current dial set: ' +\
                  str(count)
        dsh_utils.give_news(message, logging.info)
    else:
        dsh_django_utils.check_auto_timed_calls_for_all_persons(noLogging=True)
        
    message = 'triggered by dsh_reschedule.py.  done'
    dsh_agi.report_event(message, action='RESC', sessionID=sessionID)
    dsh_utils.give_news(message, logging.info)
Esempio n. 21
0
def is_triggered_by_dial_now(dshUid):
    """
    the indicator is like: '__DIAL_NOW__'
    if this is triggered as "dial now," the indicator is postfixed by
    the real dsh_uid.
    """

    dialNowIndicator = dsh_django_config.lookup("DIAL_NOW_INDICATOR")
    indicLen = len(dialNowIndicator)
    prefix = dshUid[:indicLen]
    postfix = dshUid[indicLen:]

    if prefix == dialNowIndicator:
        #
        # this dot call is triggered as a result of hitting the
        # dial-now icon.  we're not re-arming.
        #
        message = "dsh_failed.is_triggered_by_dial_now: " + postfix
        dsh_agi.report_event(message, sessionID=get_session())
        dsh_utils.give_news(message, logging.info)
        return True

    return False
def read_back_caller_number(item, fromPhone=False, sessionID=''):
    """
    10/04/09: called by demo_reply().  read back the phone number of the
    most recent caller.
    """

    response = ''
    funcName = 'dsh_common_agi.read_back_caller_number:'
    
    caller = item.owner
    phoneNumber = caller.phone_number

    if not phoneNumber:
        message = '%s no phone number: %s.' % (funcName, caller.dsh_uid)
        response += dsh_utils.red_error_break_msg(message)
        dsh_agi.report_event(message, reportLevel='ERR', sessionID=sessionID)
        dsh_utils.give_bad_news(message, logging.error)
        return (False, response)

    message = 'Send an immediate reply to %s @ %s? ' %\
              (caller.__unicode__(), phoneNumber)
    message += '<a href="/senddemoreplyconfirmed/%s">Confirm</a>?' %\
               (item.dsh_uid,)
    response += dsh_utils.black_break_msg(message)

    if fromPhone:
        promptDir = dsh_common_config.lookup('DSH_PROMPT_DIR')
        last4 = dsh_common_config.lookup('DSH_PROMPT_DEMO_LAST4')
        dsh_agi.say_it(os.path.join(promptDir, last4))
        howManyDigits = dsh_config.lookup('HIDE_PHONE_DIGITS')
        lastDigits = phoneNumber[-howManyDigits:]
        dsh_utils.give_news(
            'demo to phone: %s, last 4 digits: %s.' %\
            (phoneNumber, lastDigits), logging.info)
        say_digits(lastDigits)

    return (True, response)
Esempio n. 23
0
def maybe_deactivate_personal_message(item):
    """if all the intended audience has heard this item,
    de-activate it."""
    allAudience = item.intended_audience.all()
    if not allAudience:
        dsh_utils.db_print('dsh_django1.maybe_deactivate_personal_message: '+\
                           item.dsh_uid, 108)
        return
    for caller in allAudience:
        heardEvents = Event.objects.filter(
            action='HERD',owner=caller.id, dsh_uid_concerned=item.dsh_uid)
        if not heardEvents:
            dsh_utils.db_print(
                'dsh_django1.maybe_deactivate_personal_message: ' +\
                'not heard by this caller yet: ' + caller.phone_number,
                108)
            return

    item.active = False
    item.save()
    message = 'dsh_django1.maybe_deactivate_personal_message: deactivated: '+\
              item.dsh_uid
    dsh_utils.give_news(message, logging.info)
    dsh_agi.report_event(message, item=item)
def auto_schedule_delete_all(force=False, sessionID=None):
    """
    moved from dsh_django_utils.py
    called by views.schedule_del_all().
    force=True when initiated by views.schedule_delete_all().
    """

    disableWipe = dsh_db_config.get('reschedule_wipe_disable')
    if not force and disableWipe:
        message = 'dsh_common_agi.auto_schedule_delete_all: ' +\
                  'note: wiping of existing schedule is disabled.'
        dsh_agi.report_event(message, sessionID=sessionID)
        return dsh_utils.black_break_msg(message)

    spoolDir = dsh_common_config.lookup('ASTERISK_DOT_CALL_DIR')
    if not dsh_utils.is_valid_dir(spoolDir, silence=True):
        message = 'dsh_common_agi.auto_schedule_delete_all: ' + \
                  'spool directory invalid: ' + spoolDir
        dsh_agi.report_event(message, reportLevel = 'CRT', sessionID=sessionID)
        return dsh_utils.red_error_break_msg(message)
    
    message = 'dsh_common_agi.auto_schedule_delete_all: ' +\
              'listdir() failed: ' + spoolDir
    try:
        listing = os.listdir(spoolDir)
        listing = dsh_common_db.filter_listdir_with_dbname(listing)
    except:
        dsh_agi.report_event(message, reportLevel = 'CRT', sessionID=sessionID)
        return dsh_utils.red_error_break_msg(message)

    message = dsh_utils.black_break_msg('deleting...')
    
    for one in listing:
        full = os.path.join(spoolDir, one)
        if not one:
            continue
        if os.path.isdir(full):
            continue
        if not dsh_utils.is_valid_file(full):
            continue
        if not one.endswith('.call'):
            continue

        dsh_utils.cleanup_path(
            full, 'dsh_common_agi.auto_schedule_delete_all: ')
        message += dsh_utils.black_break_msg(full)

    message += dsh_utils.black_break_msg('done.')
    return message
Esempio n. 25
0
def lookup_number_in_db(env, debugCheat=False):
    """lookup the caller info in the django database.  returns the tuple
    (pObj, phoneNumber)"""

    if debugCheat:
        env['agi_callerid'] = '06935237794'

    if not env.has_key('agi_callerid'):
        message = 'dsh_django1.lookup_number_in_db: ' + \
                  ' no phone number given by Asterisk.'
        dsh_utils.give_news(message, logging.info)
        dsh_agi.report_event(message, reportLevel='WRN')
        return None
    
    phoneNumber = env['agi_callerid']
    
    persons = Person.objects.filter(phone_number=phoneNumber)
    if not persons:
        message = 'dsh_django1.lookup_number_in_db: ' + \
                  ' phone number not found in database: ' + phoneNumber
        dsh_utils.give_news(message, logging.info)
        dsh_agi.report_event(message, reportLevel='WRN',
                             phone_number=phoneNumber)
        return (None, phoneNumber)

    if len(persons) > 1:
        message = 'dsh_django1.lookup_number_in_db: ' + \
                  'more than one person in the db has this number: ' + \
                  phoneNumber + \
                  ', the list of people are: ' + \
                  repr(persons)
        dsh_utils.give_news(message, logging.info)
        dsh_agi.report_event(message, reportLevel='INF',
                             phone_number=phoneNumber)

    #p = persons[0]
    p = persons.latest()
    answer = (p, phoneNumber)
    dsh_utils.db_print('dsh_django1.lookup_number_in_db: ' +
                       repr(answer), 98)
    return answer
def email_selections(emailAddrs, attach, comments='', urlFields=None):
    """called by views.email_selection()."""

    returnMsg = ''


    #
    # display the email addresses.
    #
    returnMsg = dsh_utils.black_break_msg('<i><u>email(s) sent to:</u></i>\n')
    for email in emailAddrs:
        returnMsg += dsh_utils.black_break_msg(email)
    returnMsg += '<BR>\n'


    #
    # deal with comments: display them, include them.
    #
    emailText = ''
    if comments:
        returnMsg += '<i><u>comments:</u></i><br>\n'
        returnMsg += comments
        returnMsg += '<br><br>'
        emailText = '[comments:]\n\n%s\n' % (comments,)
        emailText += '\n---------------\n\n'


    #
    # now loop through all the selected items.
    #
    returnMsg += dsh_utils.black_break_msg('<i><u>items sent:</u></i><br>\n')
    
    selectedItems = dv2.db.models.Item.objects.filter(u17=True)
    if not selectedItems:
        returnMsg += dsh_utils.red_error_break_msg(
            'no item selected currently.')
        return returnMsg

    #
    # 09/11/14:
    # reverse it so it's in reverse chronological order.
    # for some reason, this didn't work...
    #
    #selectedItems.reverse()
    

    count = 0
    displayText = '<TABLE border=1>\n'
    fileList = []
    attachedFileList = []
    

    #
    # 09/11/14:
    # reverse it so it's in reverse chronological order.
    #
    for item in selectedItems[::-1]:

        emailText += smart_unicode(item.email_text(attach=attach,
                                                   urlFields=urlFields))
        emailText += '\n---------------\n\n'

        
        displayText += '<TR><TD>%s</TD></TR>\n' % \
                       (item.email_text(br=True, attach=attach,
                                        urlFields=urlFields,
                                        allowTags=True),)

        if attach:
            file = item.full_file_path()
            attachedFile = item.attachment_file_name()
        
            if file and attachedFile:
                fileList.append(file)
                attachedFileList.append(attachedFile)
            
    displayText += '</TABLE>\n'
    returnMsg += smart_unicode(displayText)
    
    returnMsg += dsh_utils.black_break_msg_debug('', 118)
    returnMsg += dsh_utils.black_break_msg_debug(repr(fileList), 118)
    returnMsg += dsh_utils.black_break_msg_debug('', 118)
    returnMsg += dsh_utils.black_break_msg_debug(repr(attachedFileList), 118)

    emailText = smart_unicode(emailText)
    emailText = smart_str(emailText)


    #
    # got everything.  ready to actually call gmail_send().
    #
    try:
        success,errorMsg = dsh_utils.gmail_send(
            dsh_config.lookup('GMAIL_SENDER_ADDRESS'),
            dsh_config.lookup('GMAIL_SENDER_PASSWORD'),
            emailAddrs,
            dsh_config.lookup('GMAIL_SENDER_SUBJECT'),
            emailText,
            attachedFiles=fileList,
            attachmentNames=attachedFileList)
        if success:
            message = 'selection emailed to: %s.  comments: %s.' %\
                      (', '.join(emailAddrs), comments)
            dsh_agi.report_event(message, action='EMAI')
            returnMsg += '<br>' + dsh_utils.black_break_msg('Message sent.')
        else:
            dsh_django_utils.error_event(errorMsg, errorLevel='ERR')
            returnMsg += '<br>' + dsh_utils.red_error_break_msg(errorMsg)
    except:
        message = 'dsh_selection.email_selections: gmail_send() failed. ' +\
                  'Unexpected error.  Tell Randy about this page.'
        dsh_django_utils.error_event(message, errorLevel='ERR')
        returnMsg += '<br>' + dsh_utils.red_error_break_msg(message)
        
    return returnMsg
def keyword_add_del(dshUid, action='add'):
    """called by views.keyword_add() and views.keyword_del()."""
    
    errorMsg = ''
    keyWord = dsh_dump.get_foreign_key(dv2.db.models.KeyWord, dshUid)
    if not keyWord:
        message = 'dsh_selection.keyword_add_del: bad key word dshUid: ' +\
                  repr(dshUid)
        dsh_django_utils.error_event(message, errorLevel='ERR')
        errorMsg += dsh_utils.red_error_break_msg(message)
        return errorMsg

    selectedItems = dv2.db.models.Item.objects.filter(u17=True)
    if not selectedItems:
        errorMsg += dsh_utils.red_error_break_msg(
            'no item selected currently.')
        return errorMsg

    count = 0
    for item in selectedItems:
        kwList = item.key_words.all()
        if action == 'add':
            if keyWord in kwList:
                continue
            try:
                item.key_words.add(keyWord)
                item.save(noLogging=True)
                count += 1
            except:
                message = 'dsh_selection.key_word_add_del: key word add ' +\
                          'failed: ' + repr(dshUid)
                dsh_django_utils.error_event(message, errorLevel='CRT')
                errorMsg += dsh_utils.red_error_break_msg(message)
                return errorMsg
        elif action == 'del':
            if not (keyWord in kwList):
                continue
            try:
                item.key_words.remove(keyWord)
                item.save(noLogging=True)
                count += 1
            except:
                message = 'dsh_selection.key_word_add_del: key word del ' +\
                          'failed: ' + repr(dshUid)
                dsh_django_utils.error_event(message, errorLevel='CRT')
                errorMsg += dsh_utils.red_error_break_msg(message)
                return errorMsg
        else:
            return dsh_utils.red_error_break_msg('bad action: ' + action)

    if action == 'add':
        actDone = 'added to'
        logAction = 'KADD'
    elif action == 'del':
        actDone = 'removed from'
        logAction = 'KDEL'
    else:
        return dsh_utils.red_error_break_msg('bad action: ' + action)

    keyStr = keyWord.key_word
    message = 'key word "%s" %s %s items.' % (keyStr, actDone, str(count))
    errorMsg += dsh_utils.black_break_msg(message)

    dsh_agi.report_event(
        message,
        action=logAction,
        item=keyWord)
    
    return errorMsg
Esempio n. 28
0
def hangup_signal_handler(signum, frame):
    """attempt to do file format conversion upon a hangup.
    from .wav to .mp3.
    after conversion, we put it in the django database."""
    
    dsh_utils.db_print2('dsh_django1.signal_handler: entered...', 101)


    #
    # get the name of the file that was just recorded.
    #
    if not globals4signal.has_key('in_file'):
        dsh_utils.give_news('dsh_django1.hangup_signal_handler: ' +
                            'hangup before recording.', logging.info)
        sys_exit(0)

    inputFile = globals4signal['in_file']


    #
    # the recorded format is wav? if not, we don't convert.
    #
    fileFormat = dsh_config.lookup('record_file_format')
    if fileFormat != 'wav':
        message = 'dsh_django1.hangup_signal_handler: ' + \
                  "can't convert non-wav file: " + inputFile
        dsh_utils.give_bad_news(message, logging.error)
        dsh_agi.report_event(message, reportLevel='ERR')
        sys_exit(1)


    #
    # does the .wav file exist and is it non-zero sized?
    #
    inputWav = inputFile + '.wav'
    success,bytes = dsh_utils.get_file_size(inputWav)
    if not success:
        message = 'dsh_django1.hangup_signal_handler: ' + \
                  'no input file to convert: ' + \
                  inputWav
        dsh_utils.give_news(message, logging.info)
        #
        # looks like we could get this far even if there's
        # a hangup before record.  that's because the
        # signal doesn't seem to be delivered fast enough.
        # so globals4signal['in_file'] gets set anyhow.
        #
        #dsh_agi.report_event(message, reportLevel='ERR')
        sys_exit(1)
    if bytes == 0:
        message = 'dsh_django1.hangup_signal_handler: ' + \
                  'inputfile size 0: ' + inputWav
        dsh_utils.give_news(message, logging.info)
        dsh_agi.report_event(message, reportLevel='WRN')
        sys_exit(1)

    dsh_utils.db_print2('dsh_django1.signal_handler: ready to convert: ' +
                        inputWav, 101)


    #
    # where's the lame binary?
    #
    lamePath = dsh_config.lookup('lame_location')
    if not dsh_utils.is_valid_file(lamePath,
                                   msg='dsh_django1.hangup_signal_handler:'):
        message = 'dsh_django1.hangup_signal_handler: ' + \
                  'need to install lame.'
        dsh_utils.give_bad_news(message, logging.error)
        dsh_agi.report_event(message, reportLevel='CRT')
        sys_exit(1)


    #
    # stdout and stderr redirected to the log directory.
    #
    stdLogs = dsh_bizarro.stdio_logs_open(globals4signal['log_dir'])
    if not stdLogs:
        sys_exit(1)
    stdout,stderr = stdLogs


    #
    # the conversion command should be:
    # lame --resample 22.05 -b 24 test.wav test4.mp3
    #
    mp3Quality = dsh_config.lookup('lame_mp3_quality')
    outputMp3 = inputFile + '.mp3'
    #command = ffmpegPath + ' -i ' + inputWav + mp3Quality + outputMp3
    command = lamePath + mp3Quality + inputWav + ' ' + outputMp3

    try:
        ret = subprocess.call(command, shell=True,
                              stdout=stdout, stderr=stderr)
    except:
        ret = -1
        
    if ret != 0:
        message = 'dsh_django1.signal_handler: ' + \
                  'error in format conversion: ' + \
                  command
        dsh_utils.give_bad_news(message, logging.error)
        dsh_agi.report_event(message, reportLevel='CRT')
        sys_exit(1)

    dsh_utils.give_news('dsh_django1.signal_handler: conversion success: ' +
                        command, logging.info)

    dsh_utils.chmod_tree2(outputMp3, recurse=False)
    
    if not dsh_utils.cleanup_path(inputWav, 'dsh_django1.signal_handler'):
        message = 'dsh_django1.signal_handler: ' + \
                  'failed to remove original wav: ' + \
                  inputWav
        dsh_utils.give_bad_news(message, logging.warning)
        dsh_agi.report_event(message, reportLevel='WRN')


    #
    # calculate some more fields for saving in the database.
    #
    callDur,recDur = calculate_durations()
    dsh_utils.db_print2('dsh_django1.signal_handler: durations are: ' +
                        str(callDur) + ', ' + str(recDur), 101)


    #
    # dirPrefix is: /u/rywang/phone_data/django/
    # chop that off.
    # so what's left is:  /media/voice/09/07/090729_215817_85983050_08935237794_unknown-org_no-name.mp3
    # no, need to chop of '/media/' as well!
    # otherwise deletes don't work!
    #
    dirPrefix = dsh_config.lookup('PHONE_DATA_DJANGO_PATH')
    choppedFileName = outputMp3.replace(dirPrefix, '/')
    #chopAbsURLPrefix = dsh_config.lookup('ABS_URL_PREFIX_CHOP')
    #choppedFileName = choppedFileName.replace(chopAbsURLPrefix, '')
    choppedFileName = dsh_agi.abs_url_to_relative(choppedFileName)
    dsh_utils.db_print2('dsh_django1.signal_handler: choppedFileName is: '+\
                        choppedFileName, 105)


    #
    # FINALLY save the object in the django database!
    #
    item = globals4signal['db_in_obj']
    item.file = choppedFileName
    item.call_duration = callDur
    item.rec_duration = recDur
    try:
        item.save()
        dsh_utils.db_print2('dsh_django1.signal_handler: item saved: ' +
                            choppedFileName, 101)
    except:
        message = 'dsh_django1.signal_handler: saving in django failed: ' + \
                  choppedFileName, 101
        dsh_utils.give_bad_news(message, logging.critical)
        dsh_agi.report_event(message, reportLevel='CRT')
        sys_exit(1)

    #
    # no point continuing execution after hangup.
    #
    sys_exit(0)
Esempio n. 29
0
def check_personalized_messages(caller):
    """does this caller have any unheard personalized messages?"""

    #
    # does this caller have any personal messages intended for him?
    #
    messages = caller.message_for_me.all()
    dsh_utils.db_print('dsh_django1.check_personalized_message: msg: ' +\
                       repr(messages), 108)
    if not messages:
        return
    
    for msg in messages:
        #
        # the message needs to be "personalized" and it needs to be "active."
        #
        maybe_deactivate_personal_message(msg)
        if not msg.active:
            dsh_utils.db_print('not active.', 108)
            continue
        if msg.itype != 'P':
            dsh_utils.db_print('not personalized: ' + msg.itype, 108)
            continue

        #
        # has this caller heard this before?
        #
        heardEvents = Event.objects.filter(
            action='HERD', owner=caller.id, dsh_uid_concerned=msg.dsh_uid)
        if heardEvents:
            dsh_utils.db_print('already heard, skipping: ' + msg.dsh_uid, 108)
            continue

        #
        # find out the .sln file path name.
        #
        chopped = get_sln_path_for_asterisk(msg)
        dsh_utils.db_print(
            'dsh_django1.check_personalized_message: sln path: ' +\
            repr(chopped), 108)

        if not chopped:
            message = 'dsh_django1.check_personalized_message: ' +\
                      'unable to find .sln file: ' + repr(msg)
            dsh_agi.report_event(message, reportLevel='ERR')
            dsh_utils.give_bad_news(message, logging.error)
            continue

        #
        # now play the personalized message and compute how long it lasted.
        #
        beginTime = datetime.datetime.now()
        dsh_agi.say_it(chopped)
        endTime = datetime.datetime.now()
        time.sleep(1)
        deltaSeconds = (endTime - beginTime).seconds

        #
        # remember the fact that this caller has heard this message.
        #
        dsh_agi.report_event(
            'personalized message heard.',
            item=msg,
            action='HERD',
            phone_number=caller.phone_number,
            owner=caller,
            call_duration=deltaSeconds)
        dsh_utils.give_news('dsh_django1.check_personalized_message: heard: '+\
                            msg.dsh_uid, logging.info)

        #
        # if everyone has heard this personalized message,
        # we should just deactivate it.
        #
        maybe_deactivate_personal_message(msg)

        #
        # beep twice at the end of each message.
        #
        dsh_agi.say_it('beep')
        dsh_agi.say_it('beep')
Esempio n. 30
0
def main():
    global globals4signal

    globals4signal['start_time'] = datetime.datetime.now()

    init_log()

    #
    # find or create unknown org and unknown person.
    #
    try:
        unknownOrg,unknownPerson = init_unknown_org_person()
    except:
        message = 'dsh_django: init_unknown_org_person failed.'
        dsh_utils.give_bad_news(message, logging.critical)
        dsh_agi.report_event(message, reportLevel='CRT')
        sys_exit(1)

    #
    # get the outgoing voice from the database.
    #
    answer = get_outgoing_voice_from_db()
    if not answer:
        sys_exit(1)
    outVobj,outgoingVoice = answer

    #
    # get the AGI environment variables.
    #
    env = dsh_agi.read_env()
    if env == {}:
        dsh_utils.give_bad_news('dsh_django1: failed to read agi envs.',
                                logging.error)
        sys_exit(1)

    #
    # look up the phone number in the django database.
    # if not found in the database, we do something about unknown callers.
    # XXX
    #lookupResult = lookup_number_in_db(env, debugCheat=True)
    lookupResult = lookup_number_in_db(env)
    caller = determine_unknown_caller(unknownOrg, unknownPerson, lookupResult)
    dsh_utils.db_print('dsh_django1: the caller determined to be: ' +
                       repr(caller), 100)
    globals4signal['caller_dude'] = caller
    
    #
    # setting up signal handler for hangup.
    # the handler will attempt to do the file format conversion.
    # and then saving into the django database.
    #
    signal.signal(signal.SIGHUP, hangup_signal_handler)


    #
    # check whether there're any personalized messages for this caller.
    #
    check_personalized_messages(caller)
    
    
    #
    # play the outgoing file.
    #
    # XXX
    dsh_agi.say_it(outgoingVoice)
    time.sleep(1)
    dsh_agi.say_it('beep')
    dsh_agi.say_it('beep')


    #
    # determine the input file name and record it.
    #
    inVobj,incomingFullName=determine_recorded_file_name(caller, outVobj)
    if incomingFullName == None:
        dsh_utils.give_bad_news(
            'dsh_django1: determine_recorded_file_name failed: ',
            logging.critical)
        sys_exit(1)
    dsh_utils.db_print('dsh_django1: incomingFullName: ' + incomingFullName,
                       101)
    globals4signal['db_in_obj'] = inVobj
    globals4signal['start_record'] = datetime.datetime.now()
    globals4signal['in_file'] = incomingFullName
    dsh_agi.record(incomingFullName)
    dsh_utils.db_print('dsh_django1: record call ends.', 101)
    time.sleep(1)
    dsh_utils.give_news('dsh_django1: recording done.')
    dsh_agi.say_it('auth-thankyou')
    dsh_agi.say_it('vm-goodbye')

    #
    # convert file format too with a proper hangup (pressing the # key).
    #
    hangup_signal_handler(0, None)