Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions lib/Subscribe.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/// <reference types="node" />
import {EventEmitter} from 'events'

import {ExtraHeaders, Originator, OutgoingListener, SessionDirection, TerminateOptions} from './RTCSession'
import {IncomingResponse} from './SIPMessage'
import {NameAddrHeader} from './NameAddrHeader'
import {causes} from './Constants';

export interface AcceptOptions extends ExtraHeaders {
body?: string;
}

export interface SendSubscribeOptions extends ExtraHeaders {
contentType?: string;
eventHandlers?: Partial<MessageEventMap>;
}

export class Subscribe extends EventEmitter {

send(target: string, body: string, options?: SendSubscribeOptions): void;

on<T extends keyof MessageEventMap>(type: T, listener: MessageEventMap[T]): this;
}
156 changes: 156 additions & 0 deletions lib/Subscribe.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
const EventEmitter = require('events').EventEmitter;
const Logger = require('./Logger');
const JsSIP_C = require('./Constants');
const SIPMessage = require('./SIPMessage');
const Utils = require('./Utils');
const RequestSender = require('./RequestSender');

const logger = new Logger('Subscribe');

module.exports = class Subscribe extends EventEmitter
{
constructor(ua)
{
super();

this._ua = ua;
this._request = null;

}

send(target, body, options = {})
{
const originalTarget = target;

if (target === undefined || body === undefined)
{
throw new TypeError('Not enough arguments');
}

// Check target validity.
target = this._ua.normalizeTarget(target);
if (!target)
{
throw new TypeError(`Invalid target: ${originalTarget}`);
}

// Get call options.
const extraHeaders = Utils.cloneArray(options.extraHeaders);
const subscriptionDuration = options.subscriptionDuration || 1;
const contentType = options.contentType || 'text/plain';
const eventType = options.eventType;

extraHeaders.push(`Content-Type: ${contentType}`);
if (eventType === 'message-summary')
{
extraHeaders.push(`Contact: ${target}`);
extraHeaders.push(`Expires: ${subscriptionDuration}`);
extraHeaders.push(`Event: ${eventType}`);
}

this._request = new SIPMessage.OutgoingRequest(
JsSIP_C.SUBSCRIBE, target, this._ua, null, extraHeaders);

if (body)
{
this._request.body = body;
}

const request_sender = new RequestSender(this._ua, this._request, {
onRequestTimeout : () =>
{
this._onRequestTimeout();
},
onTransportError : () =>
{
this._onTransportError();
},
onReceiveResponse : (response) =>
{
this._receiveResponse(response);
}
});

request_sender.send();
}

_receiveResponse(response)
{
if (this._closed)
{
return;
}
switch (true)
{
case /^1[0-9]{2}$/.test(response.status_code):
// Ignore provisional responses.
break;

case /^2[0-9]{2}$/.test(response.status_code):
this._succeeded('remote', response);
break;

default:
{
const cause = Utils.sipErrorCause(response.status_code);

this._failed('remote', response, cause);
break;
}
}
}

_onRequestTimeout()
{
if (this._closed)
{
return;
}
this._failed('system', null, JsSIP_C.causes.REQUEST_TIMEOUT);
}

_onTransportError()
{
if (this._closed)
{
return;
}
this._failed('system', null, JsSIP_C.causes.CONNECTION_ERROR);
}

_close()
{
this._closed = true;
this._ua.destroyMessage(this);
}


_failed(originator, response, cause)
{
logger.debug('SUBSCRIBE failed');

this._close();

logger.debug('emit "failed"');

this.emit('failed', {
originator,
response : response || null,
cause
});
}

_succeeded(originator, response)
{
logger.debug('SUBSCRIBEsucceeded');

this._close();

logger.debug('emit "succeeded"');

this.emit('succeeded', {
originator,
response
});
}
};
31 changes: 31 additions & 0 deletions lib/UA.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const JsSIP_C = require('./Constants');
const Registrator = require('./Registrator');
const RTCSession = require('./RTCSession');
const Message = require('./Message');
const Subscribe = require('./Subscribe');
const Options = require('./Options');
const Transactions = require('./Transactions');
const Transport = require('./Transport');
Expand Down Expand Up @@ -257,6 +258,27 @@ module.exports = class UA extends EventEmitter
return message;
}

/**
* Send a subscription.
*
* -param {String} target
* -param {String} body
* -param {Object} [options]
*
* -throws {TypeError}
*
*/
sendSubscribe(target, body, options)
{
logger.debug('sendSubscribe()');

const subscribe = new Subscribe(this);

subscribe.send(target, body, options);

return subscribe;
}

/**
* Send a SIP OPTIONS.
*
Expand Down Expand Up @@ -742,6 +764,15 @@ module.exports = class UA extends EventEmitter
{
session.receiveRequest(request);
}
// RFC3842 - check for message waiting information
else if (request.event['event'] === 'message-summary')
{
this.emit('sipEvent', {
event : request.event,
request
});
request.reply(200);
}
else
{
logger.debug('received NOTIFY request for a non existent subscription');
Expand Down