пятница, 21 ноября 2025 г.

Debian + lightdm + xfce. Несколько мониторов в системе.

Имеется рабочее место с 3 мониторами + телевизор. Кода компьютер загружается и появляется окно ввода логина и пароля, оно расположено на не основном мониторе. Будем это исправлять.

Необходимо будет создать файл 99_user.conf в следующей директории:

/usr/share/lightdm/lightdm.conf.d

Туда запишем необходимую конфигурацию мониторов, с указанием основного и расположением относительно основного монитора дополнительных, причем один дополнительный монитор еще и повернут, а также телевизор повторяет изображение основного монитора (они одинакового разрешения). Вот пример содержимого файла:

[Seat:*]
display-setup-script=xrandr --output DVI-D-0 --auto --primary --output HDMI-0 --same-as DVI-D-0 --output HDMI-1 --rotate right --left-of DVI-D-0 --output DP-2 --right-of DVI-D-0

Следующий файл 98_user.conf создаем директории:

/usr/share/lightdm/lightdm-gtk-greeter.conf.d

Этим укажем какой монитор сделать активным.Вот пример содержимого файла:

[greeter]
active-monitor=DVI-D-0

Перезагружаем компьютер и пользуемся с удовольствием)

ПС. Посмотреть на какие выходы видеокарты подключены мониторы поможет команда xrandr.

Debian multiseat. Компьютер на нескольких пользователей.

Операционная система позволяет использовать компьютер для нескольких пользователей одновременно. Для этого конечно необходимо чтобы были заведены учетные записи нескольких пользователей в системе.

Приведу пример как я создал конфигурацию на 2 пользователя, но возможно и более, главное чтобы были необходимые компоненты и достаточно мощности компьютера. Для этого понадобиться 2 видеокарты, встроенная в процессор/материнскую плату и установленная в слот PCI Express (PCI-E), соответственно несколько мониторов и два комплекта периферии (мышь+клавиатура).

Для просмотра конфигурации текущего рабочего места нужно ввести команду, она выведет "дерево" устройств :

loginctl seat-status

Добавление устройств в новое рабочее место производим командой:

loginctl attach имя рабочего места полный путь к устройству

Вот пример добавления в рабочее место с именем seat1 видеокарты:

loginctl attach seat1 /sys/devices/pci0000:00/0000:00:02.0/0000:02:00.0/drm/card1
loginctl attach seat1 /sys/devices/pci0000:00/0000:00:02.0/0000:02:00.0/drm/renderD129
loginctl attach seat1 /sys/devices/pci0000:00/0000:00:02.0/0000:02:00.1/sound/card2

Следующим пунктом я добавил вторую звуковую карту, подключенную в слот PCI, таким образом звуки разных рабочих столов будут разделены:

loginctl attach seat1 /sys/devices/pci0000:00/0000:00:14.4/0000:06:06.0/sound/card3

Далее добавляю USB устройства, точнее USB порты куда подключены клавиатура, мышь и некоторые другие устройства, это не привязывает рабочее место к конкретной модели текущего USB устройства, и при замене например мышки, просто вставьте новую в тот же USB разъем где была старая:

loginctl attach seat1 /sys/devices/pci0000:00/0000:00:12.0/usb6/6-1
loginctl attach seat1 /sys/devices/pci0000:00/0000:00:12.0/usb6/6-2
loginctl attach seat1 /sys/devices/pci0000:00/0000:00:13.0/usb7/7-3
loginctl attach seat1 /sys/devices/pci0000:00/0000:00:16.0/usb9

Чтобы было легче искать необходимое устройство можно воспользоваться следующей командой:

udevadm monitor --environment --udev

Для этого достаем мышь, которой будет пользоваться второй пользователь, из порта USB, вводим вышеуказанную команду и затем вставляем мышь в порт. Остановить вывод команды просто нажав комбинацию клавиш "CTRL" + "C".
Интересующая строка будет содержать add, на пример:

UDEV  [8581.895083] add     /devices/pci0000:00/0000:00:12.0/usb6/6-1
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:12.0/usb6/6-1
SUBSYSTEM=usb
DEVNAME=/dev/bus/usb/006/004
DEVTYPE=usb_device
.....

Для вывода списка созданных рабочих мест вводим:

loginctl list-seats

Для просмотра конфигурации рабочего места seat1 вводим:

loginctl seat-status seat1

Тут должны отобразиться все устройства которые добавляли.

Теперь можно перезагрузить компьютер и войти в систему двумя разными учетными записями.

ПС. Если необходимо удалить все настройки рабочих мест, таким образом можно вернуть всё в начальное состояние, где все устройства "подключены" к рабочему месту по умолчанию seat0, вводим:

loginctl flush-devices

суббота, 16 августа 2025 г.

Conky + mdadm

 Решил выложить свой конфигурационный файл conky и вспомогательный файл для контроля состояния RAID массивов созданных через mdadm.
В данном варианте автоматизирован вывод дополнительной информации:

  • наименовании процессора AMD и его показателях;
  • наименовании видеокарты nVidia и её показателях;
  • о сетевых подключениях LAN (enp5s0) и Wi-Fi (wlp4s0) в зависимости от способа подключения к сети.

Содержимое conky.conf, расположенного по  следующему пути /home/$USER/.config/conky/:

--[[
Conky, a system monitor, based on torsmo
]]

conky.config = {
    alignment = 'top_right',
    background = true,
    border_width = 0,
    cpu_avg_samples = 2,
    default_color = 'white',
    default_outline_color = 'white',
    default_shade_color = 'black',
    double_buffer = true,
    draw_borders = false,
    draw_graph_borders = true,
    draw_outline = false,
    draw_shades = true,
    extra_newline = false,
    font = 'DejaVu Sans Mono:size=10',
    gap_x = 50,
    gap_y = 50,
    minimum_height = 50,
    minimum_width = 350,
    net_avg_samples = 2,
    no_buffers = true,
    out_to_console = false,
    out_to_ncurses = false,
    out_to_stderr = false,
    out_to_x = true,
    own_window = true,
    own_window_argb_value = 180,
    own_window_argb_visual = true,
    own_window_class = 'Conky',
    own_window_hints = 'sticky',
    own_window_type = 'normal',
    own_window_transparent = false,
    use_spacer = 'left',
    show_graph_range = false,
    show_graph_scale = false,
    stippled_borders = 0,
    update_interval = 1.0,
    uppercase = false,
    use_spacer = 'none',
    use_xft = true,
    xinerama_head = 1,
}

conky.text = [[
$nodename | $time
${scroll 40 $sysname $kernel on $machine}
${color green}Uptime:${alignr 1}$uptime
${color lightblue}${voffset -6}$hr$color
${color grey}CPU: ${color #FCAF3E}${execi 3600 cat /proc/cpuinfo | grep 'model name' | sed -e 's/model name.*: //' | uniq | awk '{print $0}'}
${color grey}CPU Temperature ${alignr 1}${color}${execi 10 sensors | grep 'k10|CPU' -E -A2 | grep '°C' | awk '{print $2}'}
${color grey}CPU Utilization ${alignr 1}${color}$cpu %
${color grey}CPU Frequency ${alignr 1}${color}$freq MHz
${color grey}GPU: ${color #FCAF3E}${execi 3600 nvidia-smi --query-gpu=gpu_name --format=csv,noheader,nounits} $color
${color grey}GPU Temperature ${alignr 1}${color}${execi 10 nvidia-settings -query [gpu:0]/GPUCoreTemp -t} °C
${color grey}GPU Utilization ${alignr 1}${color}${exec nvidia-smi | grep % | cut -c 71-73} %
${color grey}VRAM Utilization ${alignr 1}${color}${exec nvidia-smi | grep % | cut -c 47-64}
${color grey}GPU Power Draw ${alignr 1}${color}${exec nvidia-smi | grep % | cut -c 29-41}
${color grey}RAM Usage: ${alignr 1}${color}$mem / $memmax
$memperc% ${alignr 350}${color gold}${membar 10}
${color grey}Swap Usage: ${alignr 1}${color}$swap/$swapmax
$swapperc% ${alignr 350}${color gold}${swapbar 10}
${color lightblue}${voffset -6}$hr
${color grey}File systems:
${color lightblue}/ $color${fs_used /}/${fs_size /}
${color gold}${fs_bar 8 /}
${color lightblue}/home $color${fs_used /home}/${fs_size /home}
${color gold}${fs_bar 8 /home}
${color lightblue}/mnt/images[md121] $color${fs_used /mnt/images}/${fs_size /mnt/images}
${color gold}${fs_bar 8 /mnt/images}
${color lightblue}/mnt/multimedia[md122] $color${fs_used /mnt/multimedia}/${fs_size /mnt/multimedia}
${color gold}${fs_bar 8 /mnt/multimedia}
${color lightblue}${voffset -6}$hr
${color grey}   Name             __PID__ ${color 33E0FF}_CPU%_ ${color FF33E0}_MEM%_
${color 33E0FF}CPU% ${stippled_hr 1}
${color red}   ${top name 1} ${top pid 1} ${top cpu 1} ${top mem 1}
${color purple}   ${top name 2} ${top pid 2} ${top cpu 2} ${top mem 2}
${color orange}   ${top name 3} ${top pid 3} ${top cpu 3} ${top mem 3}
${color FF33E0}MEM% ${stippled_hr 1}
${color red}   ${top_mem name 1} ${top_mem pid 1} ${top_mem cpu 1} ${top_mem mem 1}
${color purple}   ${top_mem name 2} ${top_mem pid 2} ${top_mem cpu 2} ${top_mem mem 2}
${color orange}   ${top_mem name 3} ${top_mem pid 3} ${top_mem cpu 3} ${top_mem mem 3}
${color grey}${voffset -6}$hr
${color 33E0FF}${cpugraph cpu0 50,50 33E0FF FF0000 -tl} ${cpugraph cpu1 50,50 33E0FF FF0000 -tl} ${cpugraph cpu2 50,50 33E0FF FF0000 -tl} ${cpugraph cpu3 50,50 33E0FF FF0000 -tl} ${color FF33E0}${memgraph 50,120 FF33E0 FF0000 -tl}
${color grey}Processes:$color $processes  ${color grey}Running:$color $running_processes
${if_up enp5s0}${color lightblue}${voffset -6}$hr
${color grey}LAN up/down:${alignr 1}$color${upspeed enp5s0} / ${downspeed enp5s0}
$endif${if_up wlp4s0}${color lightblue}${voffset -6}$hr
${color grey}Wi-Fi up/down:${alignr 1}$color${upspeed wlp4s0} / ${downspeed wlp4s0}
$endif${color lightblue}${voffset -6}$hr
${color grey}md121 $color ${eval $${if_match "0" == "${execi 60 cat /proc/mdstat | grep md121 -A 1 | gawk -f ~/bin/conky4mdadm.sh --}"}$${color red}Warning!$${else}$${color green}[UU]$${endif}} ${color grey} ${diskio_read /dev/md121} ${color grey} ${diskio_write /dev/md121}
${color grey}md122 $color ${eval $${if_match "0" == "${execi 60 cat /proc/mdstat | grep md122 -A 1 | gawk -f ~/bin/conky4mdadm.sh --}"}$${color red}Warning!$${else}$${color green}[UU]$${endif}} ${color grey} ${diskio_read /dev/md122} ${color grey} ${diskio_write /dev/md122}
${color lightblue}${voffset -6}$hr
${color grey}ssd1 ${color grey} ${diskio_read /dev/sdd1} ${color grey} ${diskio_write /dev/sdd1}
${color grey}ssd2 ${color grey} ${diskio_read /dev/sdd2} ${color grey} ${diskio_write /dev/sdd2}
]]

Содержимое conky4mdadm.sh, расположенного по  следующему пути /home/$USER/bin/:

#!/bin/gawk -f
# This script checks the status of RAID arrays from /proc/mdstat
/_/ { state = 0; exit }
/blocks/ { state = 1 }
END { print state }

Файлу устанавливаем разрешение на исполнение.

ПС. Расположение окна программы привязано к правому верхнему углу первого монитора, т.к. я использую несколько мониторов и по умолчанию оно расположено не на том который мне нужен был.

вторник, 19 ноября 2024 г.

Debian + Arduino +ESP32 - фиксируем порты)

Столкнулся с необходимостью "закрепить" порт за микроконтроллером типа Arduino Nano/Uno и ESP32, особенно если кроме этих плат у вас есть другие usb устройства с виртуальным COM-портом, например такими как usb-ttl платы и др.

Создаем в каталоге /etc/udev/rules.d файл 99-usb-mk.rules со следующим содержимым:

# Fix Arduino (CH340) and ESP (CH9102)
ACTION!="add", SUBSYSTEMS!="usb", GOTO="END"
KERNEL=="ttyACM[0-9]*", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d4", SYMLINK+="ttyESP", MODE:="0660", GROUP="dialout"
KERNEL=="ttyUSB[0-9]*", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="ttyARD", MODE:="0660", GROUP="dialout"
LABEL="END"

 

Теперь можно перезагрузить компьютер или ввести команду в консоли:

udevadm control --reload

Готово. Теперь к Arduino и ESP можем обращаться через /dev/ttyARD и /dev/ttyESP соответственно.

Ну и проверьте входит ли ваш пользователь в группу dialout.

ПС. К сожалению те же платы usb-ttl могут встречаться на аналогичных микросхемах что приведет к ложной фиксации порта. 

ПСС. Добавление группы пользователю:

sudo usermod -a -G dialout $USER

среда, 20 апреля 2022 г.

x11vnc как демон

Создаем "Удаленный рабочий стол" как сервис в linux.


Создал файл следующего содержимого:

 cat > /etc/systemd/system/x11vnc.service <<\eof
[Unit]
Description=VNC Server for X11
Requires=display-manager.service
After=network-online.target ##optional for better performance
Wants=network-online.target ##optional for better performance
[Service]
ExecStart=/usr/bin/x11vnc -auth guess -display :0 -rfbauth /etc/x11vnc.pwd -shared -forever -rfbport 5909 -o /var/log/x11vnc.log
ExecStop=/usr/bin/x11vnc -R stop
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
eof
echo Zadajte parol dlja dostupa:
x11vnc -storepasswd /etc/x11vnc.pwd
echo Zapusk:
echo systemctl start x11vnc
systemctl daemon-reload

Опишу что делаем с помощью него:
- создаем файл /etc/systemd/system/x11vnc.service, который будет являться демоном системы;
- создаем пароль для доступа;
- обновляем в системе список демонов.

Основой сервера удаленных рабочих столов служит x11vnc.
Сам демон не включен в автоматический старт после загрузки системы, мне не нужен был постоянный доступ к рабочему столу. Для запуска используем:

systemctl start x11vnc

Можно включить демон на постоянно:

systemctl enable x11vnc

Пробуем подключиться. Для Windows использовал UltraVNC Viewer,  а в Debian - Remmina.

среда, 25 сентября 2019 г.

FreePBX (памятка 2)

Копируем библиотеку для 3G модема chan_dongle.so.

Создаем файл 92-ttyUSB.rules со следующим содержимым:

# ustanowka praw ttyUSB* dlja asterisk
KERNEL=="ttyUSB*", MODE="0660", OWNER="asterisk", GROUP="dialout"

Создаем файл dongle.conf со следующим содержимым:

[general]

interval=15   ; Number of seconds between trying to connect to devices

;------------------------------ JITTER BUFFER CONFIGURATION --------------------------
;jbenable = yes   ; Enables the use of a jitterbuffer on the receiving side of a
    ; Dongle channel. Defaults to "no". An enabled jitterbuffer will
    ; be used only if the sending side can create and the receiving
    ; side can not accept jitter. The Dongle channel can't accept jitter,
    ; thus an enabled jitterbuffer on the receive Dongle side will always
    ; be used if the sending side can create jitter.

;jbforce = no   ; Forces the use of a jitterbuffer on the receive side of a Dongle
    ; channel. Defaults to "no".

;jbmaxsize = 200  ; Max length of the jitterbuffer in milliseconds.

;jbresyncthreshold = 1000 ; Jump in the frame timestamps over which the jitterbuffer is
    ; resynchronized. Useful to improve the quality of the voice, with
    ; big jumps in/broken timestamps, usually sent from exotic devices
    ; and programs. Defaults to 1000.

;jbimpl = fixed   ; Jitterbuffer implementation, used on the receiving side of a Dongle
    ; channel. Two implementations are currently available - "fixed"
    ; (with size always equals to jbmaxsize) and "adaptive" (with
    ; variable size, actually the new jb of IAX2). Defaults to fixed.

;jbtargetextra = 40  ; This option only affects the jb when 'jbimpl = adaptive' is set.
    ; The option represents the number of milliseconds by which the new jitter buffer
    ; will pad its size. the default is 40, so without modification, the new
    ; jitter buffer will set its size to the jitter value plus 40 milliseconds.
    ; increasing this value may help if your network normally has low jitter,
    ; but occasionally has spikes.

;jblog = no   ; Enables jitterbuffer frame logging. Defaults to "no".
;-----------------------------------------------------------------------------------

[defaults]
; now you can set here any not required device settings as template
;   sure you can overwrite in any [device] section this default values

;context=default   ; context for incoming calls
;context=from-trunk1-cust
context=from-trunk
group=0    ; calling group
rxgain=0   ; increase the incoming volume; may be negative
txgain=0   ; increase the outgoint volume; may be negative
autodeletesms=yes  ; auto delete incoming sms
resetdongle=yes   ; reset dongle during initialization with ATZ command
u2diag=-1   ; set ^U2DIAG parameter on device (0 = disable everything except modem function) ; -1 not use ^U2DIAG command
usecallingpres=yes  ; use the caller ID presentation or not
callingpres=allowed_passed_screen ; set caller ID presentation  by default use default network settings
disablesms=no   ; disable of SMS reading from device when received
    ;  chan_dongle has currently a bug with SMS reception. When a SMS gets in during a
    ;  call chan_dongle might crash. Enable this option to disable sms reception.
    ;  default = no

;language=en   ; set channel default language
language=ru
smsaspdu=yes   ; if 'yes' send SMS in PDU mode, feature implementation incomplete and we strongly recommend say 'yes'
mindtmfgap=45   ; minimal interval from end of previews DTMF from begining of next in ms
mindtmfduration=80  ; minimal DTMF tone duration in ms
mindtmfinterval=200  ; minimal interval between ends of DTMF of same digits in ms

callwaiting=auto  ; if 'yes' allow incoming calls waiting; by default use network settings
    ; if 'no' waiting calls just ignored
disable=no   ; OBSOLETED by initstate: if 'yes' no load this device and just ignore this section

initstate=start   ; specified initial state of device, must be one of 'stop' 'start' 'remote'
    ;   'remove' same as 'disable=yes'

exten=+123456789012  ; exten for start incoming calls, only in case of Subscriber Number not available!, also set to CALLERID(ndid)

dtmf=relax   ; control of incoming DTMF detection, possible values:
    ;   off    - off DTMF tones detection, voice data passed to asterisk unaltered
    ;              use this value for gateways or if not use DTMF for AVR or inside dialplan
    ;   inband - do DTMF tones detection
    ;   relax  - like inband but with relaxdtmf option
    ;  default is 'relax' by compatibility reason

; dongle required settings
[dongle0]
context=from-trunk-Mobile-v180e
audio=/dev/ttyUSB1  ; tty port for audio connection;  no default value
data=/dev/ttyUSB2  ; tty port for AT commands;   no default value

; or you can omit both audio and data together and use imei=123456789012345 and/or imsi=123456789012345
;  imei and imsi must contain exactly 15 digits !
;  imei/imsi discovery is available on Linux only
imei=123456789012345
imsi=123456789012345

; if audio and data set together with imei and/or imsi audio and data has precedence
;   you can use both imei and imsi together in this case exact match by imei and imsi required



редактируем файл extensions_custom.conf:

[from-trunk-Mobile]
exten => _X!,1,Noop(from-pstn-custom,${CALLERID(num)},${CHANNEL(linkedid)})
exten => _X!,n,System(echo ${CHANNEL(linkedid)}_${UNIQUEID}_${EXTEN} > /tmp/tr_${CHANNEL(linkedid)}.txt)
exten => _X!,n,System(echo ${CALLERID(num)} >> /tmp/tr_${CHANNEL(linkedid)}.txt)
exten => _X!,n,Set(__IN_CALLERID=${CALLERID(num)})
exten => _X!,n,Set(__IN_CALLERID=${IF($[${LEN(${IN_CALLERID})}=6]?375162${IN_CALLERID}:${IF($["${IN_CALLERID:0:2}"="80"]?375${IN_CALLERID:2}:${IF($["${IN_CALLERID:0:1}"="8"]?375${IN_CALLERID:1}:${IF($["${IN_CALLERID:0:4}"="+375"]?${IN_CALLERID:1}:${IN_CALLERID})})})})})
exten => _X!,n,Set(CALLERID(num)=${IN_CALLERID})
exten => _X!,n,Set(CALLERID(name)=${CALLERID(num)})
exten => _X!,n,System(echo ${CALLERID(num)} >> /tmp/tr_${CHANNEL(linkedid)}.txt)
exten => _X!,n,Goto(from-trunk,${EXTEN},1)

FreePBX (памятка 1)


extensions_override_freepbx.conf - правки через подключение по ssh или напрямую на сервере FreePBX. Скопировав готовые правила, добавим запуск своих скриптов:
 
[macro-dial-one]
include => macro-dial-one-custom
exten => s,1,Set(DEXTEN=${ARG3})
exten => s,n,Set(__CRM_SOURCE=${CALLERID(num)})
exten => s,n(setexttocall),ExecIf($[${LEN(${EXTTOCALL})}=0 & ${LEN(${DEXTEN})}>0]?Set(__EXTTOCALL=${DEXTEN}))
exten => s,n,Set(DIALSTATUS_CW=)
exten => s,n,GosubIf($["${FROM_DID}"!="" & "${SCREEN}"="" & "${SIGNORE}"="" & "${DB(AMPUSER/${DEXTEN}/screen)}"!=""]?screen,1())
exten => s,n,GosubIf($["${DB(CF/${DEXTEN})}"!=""]?cf,1())
exten => s,n,GotoIf($["${DEXTEN:-1}"="#" | "${DB(DND/${DEXTEN})}"=""]?skip1)
exten => s,n,Set(DEXTEN=)
exten => s,n,Set(DIALSTATUS=BUSY)
exten => s,n(skip1),GotoIf($["${DEXTEN}"=""]?nodial)
exten => s,n,GotoIf($["${DEXTEN:-1}"="#"]?continue)
exten => s,n,Set(EXTHASCW=${IF($["${CWIGNORE}"!=""]? :${DB(CW/${DEXTEN})})})
exten => s,n,GotoIf($["${EXTHASCW}"="" | "${DB(CFB/${DEXTEN})}"!="" | "${DB(CFU/${DEXTEN})}"!=""]?next1:cwinusebusy)
exten => s,n(next1),GotoIf($["${DB(CFU/${DEXTEN})}"!="" & ("${EXTENSION_STATE(${DEXTEN})}"="UNAVAILABLE" | "${EXTENSION_STATE(${DEXTEN})}"="UNKNOWN")]?docfu:skip3)
exten => s,n(docfu),Set(DEXTEN=)
exten => s,n,Set(DIALSTATUS=NOANSWER)
exten => s,n,Goto(nodial)
exten => s,n(skip3),GotoIf($["${EXTHASCW}"="" | "${DB(CFB/${DEXTEN})}"!=""]?next2:continue)
exten => s,n(next2),GotoIf($["${EXTENSION_STATE(${DEXTEN})}"="NOT_INUSE" | "${EXTENSION_STATE(${DEXTEN})}"="UNAVAILABLE" | "${EXTENSION_STATE(${DEXTEN})}"="UNKNOWN"]?continue)
exten => s,n,ExecIf($["${DB(CFB/${DEXTEN})}"!="" & "${CFIGNORE}"=""]?Set(DIALSTATUS=BUSY))
exten => s,n,GotoIf($["${EXTHASCW}"!="" | "${DEXTEN:-1}"="#"]?cwinusebusy)
exten => s,n,Set(DEXTEN=)
exten => s,n,Set(DIALSTATUS=BUSY)
exten => s,n,Goto(nodial)
exten => s,n(cwinusebusy),GotoIf($["${EXTHASCW}"!="" & "${CWINUSEBUSY}"="true"]?next3:continue)
exten => s,n(next3),ExecIf($["${EXTENSION_STATE(${DEXTEN})}"!="UNAVAILABLE" & "${EXTENSION_STATE(${DEXTEN})}"!="NOT_INUSE" & "${EXTENSION_STATE(${DEXTEN})}"!="UNKNOWN"]?Set(DIALSTATUS_CW=BUSY))
exten => s,n(continue),GotoIf($["${DEXTEN}"=""]?nodial)
exten => s,n,GosubIf($["${DEXTEN:-1}"!="#"]?dstring,1():dlocal,1())
exten => s,n,GotoIf($[${LEN(${DSTRING})}=0]?nodial)
exten => s,n,GotoIf($["${DEXTEN:-1}"="#"]?skiptrace)
exten => s,n,GosubIf($[${REGEX("^[\+]?[0-9]+$" ${CALLERID(number)})} = 1]?ctset,1():ctclear,1())
exten => s,n(skiptrace),Set(D_OPTIONS=${IF($["${NODEST}"!="" & ${REGEX("(M[(]auto-blkvm[)])" ${ARG2})} != 1]?${ARG2}M(auto-blkvm):${ARG2}M(my-1^${ARG1}^${CDR(cnam)}^${ARG3}))})
exten => s,n,GosubIf($["${ALERT_INFO}"!="" & "${HASH(SIPHEADERS,Alert-Info)}"=""]?func-set-sipheader,s,1(Alert-Info,${ALERT_INFO}))
exten => s,n,Noop(Blind Transfer: ${BLINDTRANSFER}, Attended Transfer: ${ATTENDEDTRANSFER}, User: ${AMPUSER}, Alert Info: ${ALERT_INFO})
exten => s,n,ExecIf($["${ALERT_INFO}"="" & ${LEN(${AMPUSER})}!=0 & ${LEN(${BLINDTRANSFER})}=0 & ${LEN(${ATTENDEDTRANSFER})}=0]?Set(ALERT_INFO=))
exten => s,n,ExecIf($[${LEN(${BLINDTRANSFER})}!=0]?Set(ALERT_INFO=))
exten => s,n,ExecIf($[${LEN(${ATTENDEDTRANSFER})}!=0]?Set(ALERT_INFO=))
exten => s,n,ExecIf($["${RVOL}"!=""]?Set(ALERT_INFO=${IF($["${ALERT_INFO}"!=""]?${ALERT_INFO}:Normal)}\;volume=${RVOL}))
exten => s,n,ExecIf($["${RVOL}"="" & "${DB(AMPUSER/${EXTTOCALL}/rvolume)}" != ""]?Set(ALERT_INFO=${IF($["${ALERT_INFO}"!=""]?${ALERT_INFO}:Normal)}\;volume=${DB(AMPUSER/${EXTTOCALL}/rvolume)}))
exten => s,n,GosubIf($["${ALERT_INFO}"!="" & "${ALERT_INFO}"!=" "]?func-set-sipheader,s,1(Alert-Info,${ALERT_INFO}))
exten => s,n,ExecIf($[("${MOHCLASS}"!="default") & ("${MOHCLASS}"!="")]?Set(CHANNEL(musicclass)=${MOHCLASS}))
exten => s,n,GosubIf($["${QUEUEWAIT}"!=""]?qwait,1())
exten => s,n,Set(__CWIGNORE=${CWIGNORE})
exten => s,n,Set(__KEEPCID=TRUE)
exten => s,n,GotoIf($["${USEGOTO}"="1"]?usegoto,1)
exten => s,n,GotoIf($["${DB(AMPUSER/${EXTTOCALL}/cidname)}" = "" || "${DB(AMPUSER/${AMPUSER}/cidname)}" = ""]?godial)
exten => s,n,Gosub(sub-presencestate-display,s,1(${EXTTOCALL}))
exten => s,n,Set(CONNECTEDLINE(name,i)=${DB(AMPUSER/${EXTTOCALL}/cidname)}${PRESENCESTATE_DISPLAY})
exten => s,n,Set(CONNECTEDLINE(num)=${EXTTOCALL})
exten => s,n,Set(D_OPTIONS=${D_OPTIONS}I)
exten => s,n(godial),Macro(dialout-one-predial-hook,)
exten => s,n,ExecIf($["${DIRECTION}" = "INBOUND"]?Set(D_OPTIONS=${STRREPLACE(D_OPTIONS,T)}I))
exten => s,n(dialapp),Noop()
exten => s,n,ExecIf($["${ivrreturn}" = "1"]?Set(D_OPTIONS=${D_OPTIONS}g))
exten => s,n(dial),Dial(${DSTRING},${ARG1},${D_OPTIONS}b(func-apply-sipheaders^s^1))
exten => s,n,ExecIf($["${DIALSTATUS}"="ANSWER" & "${CALLER_DEST}"!=""]?MacroExit())
exten => s,n,ExecIf($["${DIALSTATUS_CW}"!=""]?Set(DIALSTATUS=${DIALSTATUS_CW}))
exten => s,n,GosubIf($[("${SCREEN}"!=""&("${DIALSTATUS}"="TORTURE"|"${DIALSTATUS}"="DONTCALL"))|"${DIALSTATUS}"="ANSWER"]?s-${DIALSTATUS},1())
exten => s,n,MacroExit()
exten => s,n(nodial),Noop()
exten => s,n,ExecIf($["${DIALSTATUS}" = ""]?Set(DIALSTATUS=NOANSWER))
exten => s,n,Noop(Returned from dial-one with nothing to call and DIALSTATUS: ${DIALSTATUS})
exten => s,n,MacroExit()
exten => s,n,GotoIf($["${ZULU_RAW_TYPE}"!="Sangomacrm-url"]?crm-save)
exten => s,n,AGI(sangomacrm.agi,true)
exten => s,n,Goto(zulu-event)
exten => s,n(crm-save),AGI(sangomacrm.agi)
 
exten => h,1,Macro(hangupcall,)
 
exten => usegoto,1,Set(USEGOTO=)
exten => usegoto,n,Goto(from-internal,${DSTRING},1)
 
exten => screen,1,GotoIf($["${DB(AMPUSER/${DEXTEN}/screen)}"!="nomemory" | "${CALLERID(number)}"=""]?memory)
exten => screen,n,ExecIf($[${REGEX("^[0-9a-zA-Z ]+$" ${CALLERID(number)})} = 1]?System(rm -f ${ASTVARLIBDIR}/sounds/priv-callerintros/${CALLERID(number)}.*))
exten => screen,n(memory),Set(__SCREEN=${DB(AMPUSER/${DEXTEN}/screen)})
exten => screen,n,Set(__SCREEN_EXTEN=${DEXTEN})
exten => screen,n,Set(ARG2=${ARG2}p)
exten => screen,n,Return()
 
exten => cf,1,Set(CFAMPUSER=${IF($["${AMPUSER}"=""]?${CALLERID(number)}:${AMPUSER})})
exten => cf,n,ExecIf($["${DB(CF/${DEXTEN})}"="${CFAMPUSER}" | "${DB(CF/${DEXTEN})}"="${REALCALLERIDNUM}" | "${CUT(CUT(BLINDTRANSFER,-,1),/,1)}" = "${DB(CF/${DEXTEN})}" | "${DEXTEN}"="${DB(CF/${DEXTEN})}"]?Return())
exten => cf,n,ExecIf($["${DB(AMPUSER/${DEXTEN}/cfringtimer)}" != "0" & "${DB(AMPUSER/${DEXTEN}/cfringtimer)}" != ""]?Set(ARG1=${IF($["${DB(AMPUSER/${DEXTEN}/cfringtimer)}"="-1"]? : ${DB(AMPUSER/${DEXTEN}/cfringtimer)})}))
exten => cf,n,ExecIf($["${DB(AMPUSER/${DEXTEN}/cfringtimer)}" == "0"]?Set(ARG1=${IF($["${DB(FREEPBXCONF/CFRINGTIMERDEFAULT)}"="-1"]? : ${DB(FREEPBXCONF/CFRINGTIMERDEFAULT)})}))
exten => cf,n,Set(DEXTEN=${IF($["${CFIGNORE}"=""]?"${DB(CF/${DEXTEN})}#": )})
exten => cf,n,ExecIf($["${DEXTEN}"!=""]?Return())
exten => cf,n,Set(DIALSTATUS=NOANSWER)
exten => cf,n,Return()
 
exten => qwait,1,ExecIf($["${SAVEDCIDNAME}" = ""]?Set(__SAVEDCIDNAME=${CALLERID(name)}))
exten => qwait,n,Set(ELAPSED=${MATH($[${EPOCH}+30-${QUEUEWAIT}]/60,int)})
exten => qwait,n,Set(CALLERID(name)=M${ELAPSED}:${SAVEDCIDNAME})
exten => qwait,n,Return()
 
exten => ctset,1,Set(DB(CALLTRACE/${DEXTEN})=${CALLERID(number)})
exten => ctset,n,Return()
 
exten => ctclear,1,Noop(Deleting: CALLTRACE/${DEXTEN} ${DB_DELETE(CALLTRACE/${DEXTEN})})
exten => ctclear,n,Return()
 
exten => dstring,1,Set(DSTRING=)
exten => dstring,n,Set(DEVICES=${DB(AMPUSER/${DEXTEN}/device)})
exten => dstring,n,ExecIf($["${DEVICES}"=""]?Return())
exten => dstring,n,ExecIf($["${DEVICES:0:1}"="&"]?Set(DEVICES=${DEVICES:1}))
exten => dstring,n,Set(LOOPCNT=${FIELDQTY(DEVICES,&)})
exten => dstring,n,Set(ITER=1)
exten => dstring,n(begin),Set(THISDIAL=${DB(DEVICE/${CUT(DEVICES,&,${ITER})}/dial)})
exten => dstring,n,GosubIf($["${ASTCHANDAHDI}" = "1"]?zap2dahdi,1())
exten => dstring,n,GotoIf($["${THISDIAL:0:5}"!="PJSIP"]?docheck)
exten => dstring,n,Noop(Debug: Found PJSIP Destination ${THISDIAL})
exten => dstring,n,GotoIf($[ ${REGEX("(/.+/|@)" ${THISDIAL})} = 1 ]?doset)
exten => dstring,n,Noop(Debug: Updating PJSIP Destination with PJSIP_DIAL_CONTACTS)
exten => dstring,n,Set(THISDIAL=${PJSIP_DIAL_CONTACTS(${THISDIAL:6})})
exten => dstring,n,ExecIf($["${THISDIAL}"=""]?Set(DIALSTATUS=CHANUNAVAIL))
exten => dstring,n(docheck),GotoIf($["${THISDIAL}"=""]?skipset)
exten => dstring,n(doset),Set(DSTRING=${DSTRING}${THISDIAL}&)
exten => dstring,n(skipset),Set(ITER=$[${ITER}+1])
exten => dstring,n,GotoIf($[${ITER}<=${LOOPCNT}]?begin)
exten => dstring,n,ExecIf($["${DSTRING:-1}"!="&"]?Return())
exten => dstring,n,Set(DSTRING=${DSTRING:0:$[${LEN(${DSTRING})}-1]})
exten => dstring,n,Return()
 
exten => dlocal,1,Set(DSTRING=${IF($["${ARG1}"=""]?${DEXTEN:0:${MATH(${LEN(${DEXTEN})}-1,int)}}:Local/${DEXTEN:0:${MATH(${LEN(${DEXTEN})}-1,int)}}@from-internal/n)})
exten => dlocal,n,Set(USEGOTO=${IF($["${ARG1}"=""]?1:0)})
exten => dlocal,n,Return()
 
exten => zap2dahdi,1,ExecIf($["${THISDIAL}" = ""]?Return())
exten => zap2dahdi,n,Set(NEWDIAL=)
exten => zap2dahdi,n,Set(LOOPCNT2=${FIELDQTY(THISDIAL,&)})
exten => zap2dahdi,n,Set(ITER2=1)
exten => zap2dahdi,n(begin2),Set(THISPART2=${CUT(THISDIAL,&,${ITER2})})
exten => zap2dahdi,n,ExecIf($["${THISPART2:0:3}" = "ZAP"]?Set(THISPART2=DAHDI${THISPART2:3}))
exten => zap2dahdi,n,Set(NEWDIAL=${NEWDIAL}${THISPART2}&)
exten => zap2dahdi,n,Set(ITER2=$[${ITER2} + 1])
exten => zap2dahdi,n,GotoIf($[${ITER2} <= ${LOOPCNT2}]?begin2)
exten => zap2dahdi,n,Set(THISDIAL=${NEWDIAL:0:$[${LEN(${NEWDIAL})}-1]})
exten => zap2dahdi,n,Return()
 
exten => s-ANSWER,1,Noop(Call successfully answered - Hanging up now)
exten => s-ANSWER,n,GotoIf($["${ivrreturn}" = "1"]?${IVR_CONTEXT},return,1)
exten => s-ANSWER,n(bye),Macro(hangupcall,)
 
exten => s-TORTURE,1,Goto(app-blackhole,musiconhold,1)
exten => s-TORTURE,n,Macro(hangupcall,)
 
exten => s-DONTCALL,1,Answer
exten => s-DONTCALL,n,Wait(1)
exten => s-DONTCALL,n,Zapateller()
exten => s-DONTCALL,n,Playback(ss-noservice)
exten => s-DONTCALL,n,Macro(hangupcall,)
 
exten => s-CHANUNAVAIL,1,Macro(vm,${SCREEN_EXTEN},BUSY,${IVR_RETVM})
exten => s-CHANUNAVAIL,n,GotoIf($["${ivrreturn}" = "1"]?${IVR_CONTEXT},return,1)
exten => s-CHANUNAVAIL,n(return),ExecIf($["${IVR_RETVM}"!="RETURN" | "${IVR_CONTEXT}"=""]?Hangup())
exten => s-CHANUNAVAIL,n,Return()
 
exten => s-NOANSWER,1,Macro(vm,${SCREEN_EXTEN},BUSY,${IVR_RETVM})
exten => s-NOANSWER,n,GotoIf($["${ivrreturn}" = "1"]?${IVR_CONTEXT},return,1)
exten => s-NOANSWER,n(return),ExecIf($["${IVR_RETVM}"!="RETURN" | "${IVR_CONTEXT}"=""]?Hangup())
exten => s-NOANSWER,n,Return()
 
exten => s-BUSY,1,Macro(vm,${SCREEN_EXTEN},BUSY,${IVR_RETVM})
exten => s-BUSY,n,GotoIf($["${ivrreturn}" = "1"]?${IVR_CONTEXT},return,1)
exten => s-BUSY,n(return),ExecIf($["${IVR_RETVM}"!="RETURN" | "${IVR_CONTEXT}"=""]?Hangup())
exten => s-BUSY,n,Return()
 
;--== end of [macro-dial-one] ==--;
 
 
[macro-auto-blkvm]
include => macro-auto-blkvm-custom
exten => s,1,ExecIf($["${FROMQ}" = "true" & "${CALLFILENAME}" != "" & "${CDR(recordingfile)}" = ""]?Set(CDR(recordingfile)=${CALLFILENAME}.${MON_FMT}))
exten => s,n,Set(__MACRO_RESULT=)
exten => s,n,Set(CFIGNORE=)
exten => s,n,Set(MASTER_CHANNEL(CFIGNORE)=)
exten => s,n,Set(FORWARD_CONTEXT=from-internal)
exten => s,n,Set(MASTER_CHANNEL(FORWARD_CONTEXT)=from-internal)
exten => s,n,Macro(blkvm-clr,)
exten => s,n,ExecIf($[!${REGEX("[^0-9]" ${DIALEDPEERNUMBER})} && "${DB(AMPUSER/${AMPUSER}/cidname)}" != ""]?Set(MASTER_CHANNEL(CONNECTEDLINE(num))=${DIALEDPEERNUMBER}))
exten => s,n,ExecIf($[!${REGEX("[^0-9]" ${DIALEDPEERNUMBER})} && "${DB(AMPUSER/${AMPUSER}/cidname)}" != ""]?Set(MASTER_CHANNEL(CONNECTEDLINE(name))=${DB(AMPUSER/${DIALEDPEERNUMBER}/cidname)}))
exten => s,n,Macro(my-2,${DIALEDPEERNUMBER},${CALLINGPRES},${SIPCALLID})
 
;--== end of [macro-auto-blkvm] ==--;
 




extensions_custom.conf - правки через web-интерфейс FreePBX:


[from-trunk-my-custom]
exten => _X!,1,System(echo ${UNIQUEID}_${EXTEN} > /tmp/tr_${UNIQUEID}_${CALLERID(num)}.txt)
exten => _X!,n,System(echo ${CALLERID(num)} >> /tmp/tr_${UNIQUEID}_${CALLERID(num)}.txt)
exten => _X!,n,Set(_IN_CALLERID=${CALLERID(num)})
exten => _X!,n,Goto(from-trunk,${EXTEN},1)
 
[macro-my-1]
exten => s,1,Noop(macro-my-1,${CALLERID(num)},${FROMEXTEN},${TIMESTR},${UNIQUEID})
exten => s,n,Set(StrURL=http://zzz.ttttt.yyy/cgi-bin/test_01?s_=0&n_=1&e_=0&add_=)
exten => s,n,Set(ParamURL=external,${CALLERID(num)},${FROMEXTEN},${STRREPLACE(TIMESTR,"-",",")},${UNIQUEID},macro_my-1)
exten => s,n,System(echo '${StrURL}${ParamURL}' > /tmp/${UNIQUEID}_${CALLERID(num)}_1.txt)
exten => s,n,Set(SSS=${StrURL}${ParamURL})
exten => s,n,System(echo '${SSS}' >> /tmp/${UNIQUEID}_${CALLERID(num)}_1.txt)
exten => s,n,Set(CURLOPT(httptimeout)=3)
exten => s,n,Set(SSS=$[CURL(${SSS})])
exten => s,n,System(echo '${SSS}' >> /tmp/${UNIQUEID}_${CALLERID(num)}_1.txt)
exten => s,n,MacroExit()
 
[macro-my-2]
exten => s,1,Noop(macro-my-2,${CALLERID(num)},${FROMEXTEN},${TIMESTR},${UNIQUEID})
exten => s,n,Set(StrURL=http://zzz.ttttt.yyy/cgi-bin/test_02?s_=0&n_=1&e_=0&add_=)
exten => s,n,Set(ParamURL=external,${CALLERID(num)},${FROMEXTEN},${STRREPLACE(TIMESTR,"-",",")},${UNIQUEID},macro_my-2)
exten => s,n,System(echo '${StrURL}${ParamURL}' > /tmp/${UNIQUEID}_${CALLERID(num)}_2.txt)
exten => s,n,Set(SSS=${StrURL}${ParamURL})
exten => s,n,System(echo '${SSS}' >> /tmp/${UNIQUEID}_${CALLERID(num)}_2.txt)
exten => s,n,Set(CURLOPT(httptimeout)=3)
exten => s,n,Set(SSS=$[CURL(${SSS})])
exten => s,n,System(echo '${SSS}' >> /tmp/${UNIQUEID}_${CALLERID(num)}_2.txt)
exten => s,n,MacroExit()