瀏覽代碼

slack: new module, send message to slack channel

Arsen Semenov 4 年之前
父節點
當前提交
74cfb526ff

+ 31 - 0
src/modules/slack/Makefile

@@ -0,0 +1,31 @@
+#
+# Slac client for Kamailio
+#
+#
+# WARNING: do not run this directly, it should be run by the main Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=slack.so
+
+ifeq ($(CROSS_COMPILE),)
+CURL_BUILDER=$(shell \
+        if pkg-config --exists libcurl; then \
+                echo 'pkg-config libcurl'; \
+        else \
+                which curl-config; \
+        fi)
+endif
+
+ifneq ($(CURL_BUILDER),)
+        CURLDEFS += $(shell $(CURL_BUILDER) --cflags)
+        CURLLIBS += $(shell $(CURL_BUILDER) --libs)
+else
+        CURLDEFS+=-I$(LOCALBASE)/include -I$(SYSBASE)/include
+        CURLLIBS+=-L$(LOCALBASE)/lib -L$(SYSBASE)/lib -lcurl
+endif
+
+DEFS+=$(CURLDEFS)
+LIBS=$(CURLLIBS)
+
+include ../../Makefile.modules

+ 154 - 0
src/modules/slack/README

@@ -0,0 +1,154 @@
+Slack Module
+
+Arsen Semenov
+
+   <[email protected]>
+
+   Copyright © 2021 arsperger.com
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Parameters
+
+              3.1. slack url (str)
+              3.2. channel (str)
+              3.3. username (str)
+              3.4. icon_emogi (str)
+
+        4. Functions
+
+              4.1. slack_send(format)
+
+   List of Examples
+
+   1.1. Set slack webhook URL parameter
+   1.2. Set channel parameter
+   1.3. Set username parameter
+   1.4. Set icon_emogi parameter
+   1.5. slack_send usage
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Parameters
+
+        3.1. slack url (str)
+        3.2. channel (str)
+        3.3. username (str)
+        3.4. icon_emogi (str)
+
+   4. Functions
+
+        4.1. slack_send(format)
+
+1. Overview
+
+   This module provides integration with Slack over webhooks. Slack
+   integration (https://api.slack.com/messaging/webhooks)
+
+   It relays on libcurl. library (https://curl.se/libcurl).
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * none.
+
+2.2. External Libraries or Applications
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
+     * libcurl
+
+3. Parameters
+
+   3.1. slack url (str)
+   3.2. channel (str)
+   3.3. username (str)
+   3.4. icon_emogi (str)
+
+3.1. slack url (str)
+
+   Slack webhook url
+
+   Default value is not set (empty)
+
+   Example 1.1. Set slack webhook URL parameter
+...
+modparam("slack", "slack_url", "https://hooks.slack.com/services/T00000000/B0000
+0000/XXXXXXXXXXXXXXXXXXXXXXXX")
+...
+
+3.2. channel (str)
+
+   Slack channel name
+
+   Default value is #kamailio
+
+   Example 1.2. Set channel parameter
+...
+modparam("slack", "channel", "#kamailio")
+...
+
+3.3. username (str)
+
+   Specify the username for the published message
+
+   Default value is webhookbot.
+
+   Example 1.3. Set username parameter
+...
+modparam("slack", "username", "webhookbot")
+...
+
+3.4. icon_emogi (str)
+
+   specify an emoji (using colon shortcodes, eg. :white_check_mark:) to
+   use as the profile photo alongside the message.
+
+   Default value is :ghost:
+
+   Example 1.4. Set icon_emogi parameter
+...
+modparam("slack", "icon_emogi", ":ghost:")
+...
+
+4. Functions
+
+   4.1. slack_send(format)
+
+4.1.  slack_send(format)
+
+   Send a formatted message to slack channel.
+
+   The parameters are:
+     * format - The formatted string to be send.
+
+   The parameters can contain pseudo-variables.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.5. slack_send usage
+...
+    slack_send("Hello from Kamailio! caller=$fU;callee=$tU;callid=$ci");
+...

+ 4 - 0
src/modules/slack/doc/Makefile

@@ -0,0 +1,4 @@
+docs = slack.xml
+
+docbook_dir = ../../../../doc/docbook
+include $(docbook_dir)/Makefile.module

+ 468 - 0
src/modules/slack/doc/slack.html

@@ -0,0 +1,468 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <title>Slack Module</title>
+    <link rel="stylesheet" type="text/css" href="/css/sr-doc.css" />
+    <meta name="generator" content="DocBook XSL Stylesheets V1.79.1" />
+    <link rel="home" href="#idm1" title="Slack Module" />
+    <link rel="next" href="#idm14" title="Chapter 1. Admin Guide" />
+  </head>
+  <body>
+    <div class="book">
+      <div class="titlepage">
+        <div>
+          <div>
+            <h1 class="title"><a id="idm1"></a>Slack Module</h1>
+          </div>
+          <div>
+            <div class="authorgroup">
+              <div class="author">
+                <h3 class="author"><span class="firstname">Arsen</span> <span class="surname">Semenov</span></h3>
+                <code class="email">&lt;<a class="email" href="mailto:[email protected]">[email protected]</a>&gt;</code>
+              </div>
+            </div>
+          </div>
+          <div>
+            <p class="copyright">Copyright © 2021 arsperger.com</p>
+          </div>
+        </div>
+        <hr />
+      </div>
+      <div class="toc">
+        <p>
+          <strong>Table of Contents</strong>
+        </p>
+        <dl class="toc">
+          <dt>
+            <span class="chapter">
+              <a href="#idm14">1. Admin Guide</a>
+            </span>
+          </dt>
+          <dd>
+            <dl>
+              <dt>
+                <span class="section">
+                  <a href="#idm16">1. Overview</a>
+                </span>
+              </dt>
+              <dt>
+                <span class="section">
+                  <a href="#idm20">2. Dependencies</a>
+                </span>
+              </dt>
+              <dd>
+                <dl>
+                  <dt>
+                    <span class="section">
+                      <a href="#idm22">2.1. Kamailio Modules</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="section">
+                      <a href="#idm29">2.2. External Libraries or Applications</a>
+                    </span>
+                  </dt>
+                </dl>
+              </dd>
+              <dt>
+                <span class="section">
+                  <a href="#idm36">3. Parameters</a>
+                </span>
+              </dt>
+              <dd>
+                <dl>
+                  <dt>
+                    <span class="section">
+                      <a href="#slack.p.url">3.1. <code class="varname">slack url</code> (str)</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="section">
+                      <a href="#slack.p.channel">3.2. <code class="varname">channel</code> (str)</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="section">
+                      <a href="#lwsc.p.username">3.3. <code class="varname">username</code> (str)</a>
+                    </span>
+                  </dt>
+                  <dt>
+                    <span class="section">
+                      <a href="#slack.p.icon_emogi">3.4. <code class="varname">icon_emogi</code> (str)</a>
+                    </span>
+                  </dt>
+                </dl>
+              </dd>
+              <dt>
+                <span class="section">
+                  <a href="#idm78">4. Functions</a>
+                </span>
+              </dt>
+              <dd>
+                <dl>
+                  <dt>
+                    <span class="section">
+                      <a href="#slack.f.slack_send">4.1. 
+		<code class="function">slack_send(format)</code>
+	    </a>
+                    </span>
+                  </dt>
+                </dl>
+              </dd>
+            </dl>
+          </dd>
+        </dl>
+      </div>
+      <div class="list-of-examples">
+        <p>
+          <strong>List of Examples</strong>
+        </p>
+        <dl>
+          <dt>1.1. <a href="#idm44">Set <code class="varname">slack webhook URL</code> parameter</a></dt>
+          <dt>1.2. <a href="#idm54">Set <code class="varname">channel</code> parameter</a></dt>
+          <dt>1.3. <a href="#idm64">Set <code class="varname">username</code> parameter</a></dt>
+          <dt>1.4. <a href="#idm74">Set <code class="varname">icon_emogi</code> parameter</a></dt>
+          <dt>1.5. <a href="#idm90"><code class="function">slack_send</code> usage</a></dt>
+        </dl>
+      </div>
+      <div class="chapter">
+        <div class="titlepage">
+          <div>
+            <div>
+              <h1 class="title"><a id="idm14"></a>Chapter 1. Admin Guide</h1>
+            </div>
+          </div>
+        </div>
+        <div class="toc">
+          <p>
+            <strong>Table of Contents</strong>
+          </p>
+          <dl class="toc">
+            <dt>
+              <span class="section">
+                <a href="#idm16">1. Overview</a>
+              </span>
+            </dt>
+            <dt>
+              <span class="section">
+                <a href="#idm20">2. Dependencies</a>
+              </span>
+            </dt>
+            <dd>
+              <dl>
+                <dt>
+                  <span class="section">
+                    <a href="#idm22">2.1. Kamailio Modules</a>
+                  </span>
+                </dt>
+                <dt>
+                  <span class="section">
+                    <a href="#idm29">2.2. External Libraries or Applications</a>
+                  </span>
+                </dt>
+              </dl>
+            </dd>
+            <dt>
+              <span class="section">
+                <a href="#idm36">3. Parameters</a>
+              </span>
+            </dt>
+            <dd>
+              <dl>
+                <dt>
+                  <span class="section">
+                    <a href="#slack.p.url">3.1. <code class="varname">slack url</code> (str)</a>
+                  </span>
+                </dt>
+                <dt>
+                  <span class="section">
+                    <a href="#slack.p.channel">3.2. <code class="varname">channel</code> (str)</a>
+                  </span>
+                </dt>
+                <dt>
+                  <span class="section">
+                    <a href="#lwsc.p.username">3.3. <code class="varname">username</code> (str)</a>
+                  </span>
+                </dt>
+                <dt>
+                  <span class="section">
+                    <a href="#slack.p.icon_emogi">3.4. <code class="varname">icon_emogi</code> (str)</a>
+                  </span>
+                </dt>
+              </dl>
+            </dd>
+            <dt>
+              <span class="section">
+                <a href="#idm78">4. Functions</a>
+              </span>
+            </dt>
+            <dd>
+              <dl>
+                <dt>
+                  <span class="section">
+                    <a href="#slack.f.slack_send">4.1. 
+		<code class="function">slack_send(format)</code>
+	    </a>
+                  </span>
+                </dt>
+              </dl>
+            </dd>
+          </dl>
+        </div>
+        <div class="section">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title"><a id="idm16"></a>1. Overview</h2>
+              </div>
+            </div>
+          </div>
+          <p>
+		This module provides integration with Slack over webhooks.
+		Slack integration (https://api.slack.com/messaging/webhooks)
+	</p>
+          <p>
+		It relays on libcurl. library (https://curl.se/libcurl).
+	</p>
+        </div>
+        <div class="section">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title"><a id="idm20"></a>2. Dependencies</h2>
+              </div>
+            </div>
+          </div>
+          <div class="section">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="idm22"></a>2.1. Kamailio Modules</h3>
+                </div>
+              </div>
+            </div>
+            <p>
+		The following modules must be loaded before this module:
+			</p>
+            <div class="itemizedlist">
+              <ul class="itemizedlist" type="disc">
+                <li class="listitem">
+                  <p>
+				<span class="emphasis"><em>none</em></span>.
+			</p>
+                </li>
+              </ul>
+            </div>
+            <p>
+		</p>
+          </div>
+          <div class="section">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="idm29"></a>2.2. External Libraries or Applications</h3>
+                </div>
+              </div>
+            </div>
+            <p>
+		The following libraries or applications must be installed before running
+		Kamailio with this module loaded:
+			</p>
+            <div class="itemizedlist">
+              <ul class="itemizedlist" type="disc">
+                <li class="listitem">
+                  <p>
+				<span class="emphasis"><em>libcurl</em></span>
+			</p>
+                </li>
+              </ul>
+            </div>
+            <p>
+		</p>
+          </div>
+        </div>
+        <div class="section">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title"><a id="idm36"></a>3. Parameters</h2>
+              </div>
+            </div>
+          </div>
+          <div class="section">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="slack.p.url"></a>3.1. <code class="varname">slack url</code> (str)</h3>
+                </div>
+              </div>
+            </div>
+            <p>
+			Slack webhook url
+		</p>
+            <p>
+		<span class="emphasis"><em>
+			Default value is not set (empty)
+		</em></span>
+		</p>
+            <div class="example">
+              <a id="idm44"></a>
+              <p class="title">
+                <strong>Example 1.1. Set <code class="varname">slack webhook URL</code> parameter</strong>
+              </p>
+              <div class="example-contents">
+                <pre class="programlisting">...
+modparam("slack", "slack_url", "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX")
+...</pre>
+              </div>
+            </div>
+            <br class="example-break" />
+          </div>
+          <div class="section">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="slack.p.channel"></a>3.2. <code class="varname">channel</code> (str)</h3>
+                </div>
+              </div>
+            </div>
+            <p>
+			Slack channel name
+		</p>
+            <p>
+		<span class="emphasis"><em>
+			Default value is #kamailio
+		</em></span>
+		</p>
+            <div class="example">
+              <a id="idm54"></a>
+              <p class="title">
+                <strong>Example 1.2. Set <code class="varname">channel</code> parameter</strong>
+              </p>
+              <div class="example-contents">
+                <pre class="programlisting">...
+modparam("slack", "channel", "#kamailio")
+...</pre>
+              </div>
+            </div>
+            <br class="example-break" />
+          </div>
+          <div class="section">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="lwsc.p.username"></a>3.3. <code class="varname">username</code> (str)</h3>
+                </div>
+              </div>
+            </div>
+            <p>
+			Specify the username for the published message
+		</p>
+            <p>
+		<span class="emphasis"><em>
+			Default value is webhookbot.
+		</em></span>
+		</p>
+            <div class="example">
+              <a id="idm64"></a>
+              <p class="title">
+                <strong>Example 1.3. Set <code class="varname">username</code> parameter</strong>
+              </p>
+              <div class="example-contents">
+                <pre class="programlisting">...
+modparam("slack", "username", "webhookbot")
+...</pre>
+              </div>
+            </div>
+            <br class="example-break" />
+          </div>
+          <div class="section">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="slack.p.icon_emogi"></a>3.4. <code class="varname">icon_emogi</code> (str)</h3>
+                </div>
+              </div>
+            </div>
+            <p>
+			specify an emoji (using colon shortcodes, eg. :white_check_mark:)
+			to use as the profile photo alongside the message.
+		</p>
+            <p>
+		<span class="emphasis"><em>
+			Default value is :ghost:
+		</em></span>
+		</p>
+            <div class="example">
+              <a id="idm74"></a>
+              <p class="title">
+                <strong>Example 1.4. Set <code class="varname">icon_emogi</code> parameter</strong>
+              </p>
+              <div class="example-contents">
+                <pre class="programlisting">...
+modparam("slack", "icon_emogi", ":ghost:")
+...</pre>
+              </div>
+            </div>
+            <br class="example-break" />
+          </div>
+        </div>
+        <div class="section">
+          <div class="titlepage">
+            <div>
+              <div>
+                <h2 class="title"><a id="idm78"></a>4. Functions</h2>
+              </div>
+            </div>
+          </div>
+          <div class="section">
+            <div class="titlepage">
+              <div>
+                <div>
+                  <h3 class="title"><a id="slack.f.slack_send"></a>4.1. 
+		<code class="function">slack_send(format)</code>
+	    </h3>
+                </div>
+              </div>
+            </div>
+            <p>
+		Send a formatted message to slack channel.
+		</p>
+            <p>
+		The parameters are:
+		</p>
+            <div class="itemizedlist">
+              <ul class="itemizedlist" type="disc">
+                <li class="listitem">
+                  <p>
+			format - The formatted string to be send.
+			</p>
+                </li>
+              </ul>
+            </div>
+            <p>
+		The parameters can contain pseudo-variables.
+		</p>
+            <p>
+		This function can be used from ANY_ROUTE.
+		</p>
+            <div class="example">
+              <a id="idm90"></a>
+              <p class="title">
+                <strong>Example 1.5. <code class="function">slack_send</code> usage</strong>
+              </p>
+              <div class="example-contents">
+                <pre class="programlisting">...
+    slack_send("Hello from Kamailio! caller=$fU;callee=$tU;callid=$ci");
+...</pre>
+              </div>
+            </div>
+            <br class="example-break" />
+          </div>
+        </div>
+      </div>
+    </div>
+  </body>
+</html>

+ 28 - 0
src/modules/slack/doc/slack.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+	<!-- Include general documentation entities -->
+	<!ENTITY % docentities SYSTEM "../../../../doc/docbook/entities.xml">
+	%docentities;
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+	<bookinfo>
+		<title>Slack Module</title>
+		<productname class="trade">&kamailioname;</productname>
+		<authorgroup>
+			<author>
+				<firstname>Arsen</firstname>
+				<surname>Semenov</surname>
+				<email>[email protected]</email>
+			</author>
+		</authorgroup>
+		<copyright>
+			<year>2021</year>
+			<holder>arsperger.com</holder>
+		</copyright>
+	</bookinfo>
+	<toc></toc>
+
+	<xi:include href="slack_admin.xml" />
+
+</book>

+ 175 - 0
src/modules/slack/doc/slack_admin.xml

@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../../doc/docbook/entities.xml">
+%docentities;
+
+]>
+<!-- Module User's Guide -->
+
+<chapter>
+
+	<title>&adminguide;</title>
+
+	<section>
+	<title>Overview</title>
+	<para>
+		This module provides integration with Slack over webhooks.
+		Slack integration (https://api.slack.com/messaging/webhooks)
+	</para>
+	<para>
+		It relays on libcurl. library (https://curl.se/libcurl).
+	</para>
+	</section>
+
+	<section>
+	<title>Dependencies</title>
+	<section>
+		<title>&kamailio; Modules</title>
+		<para>
+		The following modules must be loaded before this module:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>none</emphasis>.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	<section>
+		<title>External Libraries or Applications</title>
+		<para>
+		The following libraries or applications must be installed before running
+		&kamailio; with this module loaded:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>libcurl</emphasis>
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	</section>
+
+	<section>
+	<title>Parameters</title>
+	<section id="slack.p.url">
+		<title><varname>slack url</varname> (str)</title>
+		<para>
+			Slack webhook url
+		</para>
+		<para>
+		<emphasis>
+			Default value is not set (empty)
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>slack webhook URL</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("slack", "slack_url", "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX")
+...
+		</programlisting>
+		</example>
+	</section>
+	<section id="slack.p.channel">
+		<title><varname>channel</varname> (str)</title>
+		<para>
+			Slack channel name
+		</para>
+		<para>
+		<emphasis>
+			Default value is #kamailio
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>channel</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("slack", "channel", "#kamailio")
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="lwsc.p.username">
+		<title><varname>username</varname> (str)</title>
+		<para>
+			Specify the username for the published message
+		</para>
+		<para>
+		<emphasis>
+			Default value is webhookbot.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>username</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("slack", "username", "webhookbot")
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="slack.p.icon_emogi">
+		<title><varname>icon_emogi</varname> (str)</title>
+		<para>
+			specify an emoji (using colon shortcodes, eg. :white_check_mark:)
+			to use as the profile photo alongside the message.
+		</para>
+		<para>
+		<emphasis>
+			Default value is :ghost:
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>icon_emogi</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("slack", "icon_emogi", ":ghost:")
+...
+</programlisting>
+		</example>
+	</section>
+
+	</section>
+
+	<section>
+	<title>Functions</title>
+	<section id="slack.f.slack_send">
+	    <title>
+		<function moreinfo="none">slack_send(format)</function>
+	    </title>
+	    <para>
+		Send a formatted message to slack channel.
+		</para>
+		<para>
+		The parameters are:
+		</para>
+		<itemizedlist>
+			<listitem>
+			<para>
+			format - The formatted string to be send.
+			</para>
+			</listitem>
+		</itemizedlist>
+		<para>
+		The parameters can contain pseudo-variables.
+		</para>
+		<para>
+		This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>slack_send</function> usage</title>
+		<programlisting format="linespecific">
+...
+    slack_send("Hello from Kamailio! caller=$fU;callee=$tU;callid=$ci");
+...
+</programlisting>
+	    </example>
+	</section>
+	</section>
+</chapter>

+ 298 - 0
src/modules/slack/slack.c

@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2021 Arsen Semenov [email protected]
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "slack.h"
+
+MODULE_VERSION
+
+static char *_slmsg_buf = NULL;
+static int mod_init(void);
+static void mod_destroy(void);
+
+static int buf_size = 4096;
+static char *slack_url = NULL;
+static char *slack_channel = SLACK_DEFAULT_CHANNEL;
+static char *slack_username = SLACK_DEFAULT_USERNAME;
+static char *slack_icon = SLACK_DEFAULT_ICON;
+
+/**
+ * Exported functions
+ */
+static cmd_export_t cmds[] = {
+	{"slack_send",	  		(cmd_function)slack_send1,			1, slack_fixup,  0, ANY_ROUTE},
+	{0, 0, 0, 0, 0, 0}
+};
+
+
+/**
+ * Exported parameters
+ */
+static param_export_t mod_params[] = {
+	{ "slack_url", 			PARAM_STRING|USE_FUNC_PARAM, (void*)_slack_url_param},
+	{ "channel",			PARAM_STRING, &slack_channel }, // channel starts with #
+	{ "username",			PARAM_STRING, &slack_username },
+	{ "icon_emogi",			PARAM_STRING, &slack_icon },
+	{0, 0, 0}
+};
+
+/**
+ * Module description
+ */
+struct module_exports exports = {
+	"slack",        /* 1 module name */
+	DEFAULT_DLFLAGS, /* 2 dlopen flags */
+	cmds,            /* 3 exported functions */
+	mod_params,      /* 4 exported parameters */
+	0,               /* 5 exported RPC functions */
+	0,         		 /* 6 exported pseudo-variables */
+	0,               /* 7 response function */
+	mod_init,        /* 8 module initialization function */
+	0,      		 /* 9 per-child init function */
+	mod_destroy      /* 0 destroy function */
+};
+
+/**
+ * Module init
+ */
+static int mod_init(void) {
+	LM_INFO("slack module init\n");
+
+	_slmsg_buf = (char*)pkg_malloc((buf_size+1)*sizeof(char));
+	if(_slmsg_buf==NULL)
+	{
+		PKG_MEM_ERROR;
+		return -1;
+	}
+	return(0);
+}
+
+/**
+ * Module destroy
+ */
+static void mod_destroy() {
+	LM_INFO("slack module destroy\n");
+	if(_slmsg_buf)
+		pkg_free(_slmsg_buf);
+	if(slack_url)
+		pkg_free(slack_url);
+	return;
+}
+
+/**
+ * send message with curl
+ * @return 0 on success, -1 on error
+ */
+static int _curl_send(const char* uri, str *post_data)
+{
+	int datasz;
+	char* send_data;
+	CURL *curl_handle;
+	CURLcode res;
+	// LM_DBG("sending to[%s]\n", uri);
+
+	datasz = snprintf(NULL, 0, BODY_FMT, slack_channel, slack_username, post_data->s, slack_icon);
+	send_data = (char*)pkg_malloc((datasz+1)*sizeof(char));
+	if(send_data==NULL) {
+        LM_ERR("Error: can not allocate pkg memory [%d] bytes\n", datasz);
+        return -1;
+    }
+    snprintf(send_data, datasz+1, BODY_FMT, slack_channel, slack_username, post_data->s, slack_icon);
+
+	curl_global_init(CURL_GLOBAL_ALL);
+
+	if((curl_handle=curl_easy_init())==NULL) {
+    	LM_ERR("Error: Unable to init cURL library\n");
+		curl_global_cleanup();
+        return -1;
+    }
+
+	curl_easy_setopt(curl_handle, CURLOPT_URL, uri);
+	curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, send_data);
+	res = curl_easy_perform(curl_handle);
+
+	if (res != CURLE_OK) {
+		LM_ERR("slack request send error: %s\n", curl_easy_strerror(res));
+		curl_easy_cleanup(curl_handle);
+		curl_global_cleanup();
+		if(send_data) {
+			pkg_free(send_data);
+		}
+		return -1;
+	}
+
+	LM_INFO("slack request sent [%d]\n", datasz);
+	curl_easy_cleanup(curl_handle);
+	curl_global_cleanup();
+	if (send_data) {
+		pkg_free(send_data);
+	}
+	return 0;
+}
+
+/**
+ * parse slack_url param2
+ */
+static int _slack_parse_url_param(char *val)
+{
+	int len;
+	len = strlen(val);
+	if(len > SLACK_URL_MAX_SIZE) {
+		LM_ERR("webhook url max size exceeded %d\n", SLACK_URL_MAX_SIZE);
+		return -1;
+	}
+
+	if(strncmp(val, "https://hooks.slack.com", 23)) {
+		LM_ERR("slack invalid webhook url [%s]\n", val);
+		return -1;
+	}
+
+	// TODO: parse webhook to multiple channels? eg.: chan1=>https://AAA/BBB/CC, chan2=>...
+
+	slack_url = (char*)pkg_malloc(len + 1);
+	if (slack_url==NULL) {
+		PKG_MEM_ERROR;
+		return -1;
+	}
+	strcpy(slack_url, val);
+	slack_url[len] = '\0';
+
+	return 0;
+}
+
+/**
+ * parse slack_url param
+ */
+int _slack_url_param(modparam_t type, void *val)
+{
+	if(val==NULL) {
+		LM_ERR("webhook url not specified\n");
+		return -1;
+	}
+
+	return _slack_parse_url_param((char*)val);
+}
+
+static int slack_fixup_helper(void** param, int param_no)
+{
+	sl_msg_t *sm;
+	str s;
+
+	sm = (sl_msg_t*)pkg_malloc(sizeof(sl_msg_t));
+	if(sm==NULL)
+	{
+		PKG_MEM_ERROR;
+		return -1;
+	}
+	memset(sm, 0, sizeof(sl_msg_t));
+	s.s = (char*)(*param);
+	s.len = strlen(s.s);
+
+	if(pv_parse_format(&s, &sm->m)<0)
+	{
+		LM_ERR("wrong format[%s]\n", (char*)(*param));
+		pkg_free(sm);
+		return E_UNSPEC;
+	}
+	*param = (void*)sm;
+	return 0;
+}
+
+
+static int slack_fixup(void** param, int param_no)
+{
+	if(param_no!=1 || param==NULL || *param==NULL)
+	{
+		LM_ERR("invalid parameter number %d\n", param_no);
+		return E_UNSPEC;
+	}
+	return slack_fixup_helper(param, param_no);
+}
+
+/**
+ * send text message to slack
+ */
+static inline int slack_helper(struct sip_msg* msg, sl_msg_t *sm)
+{
+	str txt;
+	txt.len = buf_size;
+
+	if(_slack_print_log(msg, sm->m, _slmsg_buf, &txt.len)<0)
+		return -1;
+
+	txt.s = _slmsg_buf;
+
+	return _curl_send(slack_url, &txt);
+}
+
+static int slack_send1(struct sip_msg* msg, char* frm, char* str2)
+{
+	return slack_helper(msg, (sl_msg_t*)frm);
+}
+
+
+/**
+ * Kemi
+ * send slack msg after evaluation of pvars
+ * @return 0 on success, -1 on error
+ */
+static int ki_slack_send(sip_msg_t *msg, str *slmsg)
+{
+	pv_elem_t *xmodel=NULL;
+	str txt = STR_NULL;
+	int res;
+
+	if(pv_parse_format(slmsg, &xmodel)<0) {
+		LM_ERR("wrong format[%s]\n", slmsg->s);
+		return -1;
+	}
+	if(pv_printf_s(msg, xmodel, &txt)!=0) {
+		LM_ERR("Error: cannot eval reparsed value\n");
+		pv_elem_free_all(xmodel);
+		return -1;
+	}
+
+	res = _curl_send(slack_url, &txt);
+	pv_elem_free_all(xmodel);
+	return res;
+}
+
+
+/* clang-format off */
+static sr_kemi_t sr_kemi_slack_exports[] = {
+	{ str_init("slack"), str_init("slack_send"),
+		SR_KEMIP_INT, ki_slack_send,
+		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+
+	{ {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
+};
+/* clang-format on */
+
+
+int mod_register(char *path, int *dlflags, void *p1, void *p2)
+{
+	sr_kemi_modules_add(sr_kemi_slack_exports);
+	return 0;
+}

+ 58 - 0
src/modules/slack/slack.h

@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 Arsen Semenov [email protected]
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the tertc of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+#ifndef slack_h
+#define slack_h
+
+#include "../../core/sr_module.h"
+#include "../../core/dprint.h"
+#include "../../core/parser/parse_content.h"
+#include "../../core/pvar.h"
+#include "../../core/kemi.h"
+
+#include <string.h>
+#include <curl/curl.h>
+
+#define BODY_FMT "{\"channel\": \"%s\", \"username\": \"%s\", \"text\": \"%s\", \"icon_emoji\": \"%s\" }"
+#define SLACK_URL_MAX_SIZE 128
+#define SLACK_DEFAULT_CHANNEL "#webtest"
+#define SLACK_DEFAULT_USERNAME "webhookbot"
+#define SLACK_DEFAULT_ICON ":ghost:"
+
+static int _slack_print_log(struct sip_msg* msg, pv_elem_p list, char *buf, int *len)
+{
+	return pv_printf(msg, list, buf, len);
+}
+
+static int _curl_send(const char* uri, str *post_data );
+static int _slack_parse_url_param(char *val);
+static int _slack_url_param(modparam_t type, void *val);
+
+static int slack_fixup(void** param, int param_no);
+static int slack_send1(struct sip_msg* msg, char* frm, char* str2);
+static int slack_fixup_helper(void** param, int param_no);
+
+typedef struct _sl_msg
+{
+	pv_elem_t *m;
+} sl_msg_t;
+
+#endif /* slack_h */