/src/resiprocate/resip/stack/DtmfPayloadContents.cxx
Line | Count | Source |
1 | | #if defined(HAVE_CONFIG_H) |
2 | | #include "config.h" |
3 | | #endif |
4 | | |
5 | | #include "resip/stack/DtmfPayloadContents.hxx" |
6 | | #include "resip/stack/Helper.hxx" |
7 | | #include "rutil/ParseBuffer.hxx" |
8 | | #include "rutil/DataStream.hxx" |
9 | | #include "resip/stack/Symbols.hxx" |
10 | | #include "rutil/Logger.hxx" |
11 | | #include "rutil/WinLeakCheck.hxx" |
12 | | #include "resip/stack/SdpContents.hxx" |
13 | | |
14 | | #define RESIPROCATE_SUBSYSTEM resip::Subsystem::SDP |
15 | | |
16 | | using namespace resip; |
17 | | using namespace std; |
18 | | |
19 | | //const DtmfPayloadContents DtmfPayloadContents::Empty; |
20 | | |
21 | | bool |
22 | | DtmfPayloadContents::init() |
23 | 4 | { |
24 | 4 | static ContentsFactory<DtmfPayloadContents> factory; |
25 | 4 | (void)factory; |
26 | 4 | return true; |
27 | 4 | } |
28 | | |
29 | 0 | DtmfPayloadContents::DtmfPayloadContents() : Contents(getStaticType()) |
30 | 0 | { |
31 | 0 | } |
32 | | |
33 | | DtmfPayloadContents::DtmfPayloadContents(const HeaderFieldValue& hfv, const Mime& contentTypes) |
34 | 6.05k | : Contents(hfv, contentTypes) |
35 | 6.05k | { |
36 | 6.05k | } |
37 | | |
38 | | DtmfPayloadContents::~DtmfPayloadContents() |
39 | 6.05k | { |
40 | 6.05k | } |
41 | | |
42 | | DtmfPayloadContents& |
43 | | DtmfPayloadContents::operator=(const DtmfPayloadContents& rhs) |
44 | 0 | { |
45 | 0 | if (this != &rhs) |
46 | 0 | { |
47 | 0 | Contents::operator=(rhs); |
48 | 0 | mDtmfPayload = rhs.mDtmfPayload; |
49 | 0 | } |
50 | 0 | return *this; |
51 | 0 | } |
52 | | |
53 | | Contents* |
54 | | DtmfPayloadContents::clone() const |
55 | 0 | { |
56 | 0 | return new DtmfPayloadContents(*this); |
57 | 0 | } |
58 | | |
59 | | void |
60 | | DtmfPayloadContents::parse(ParseBuffer& pb) |
61 | 6.05k | { |
62 | 6.05k | mDtmfPayload.parse(pb); |
63 | 6.05k | } |
64 | | |
65 | | EncodeStream& |
66 | | DtmfPayloadContents::encodeParsed(EncodeStream& s) const |
67 | 0 | { |
68 | 0 | mDtmfPayload.encode(s); |
69 | 0 | return s; |
70 | 0 | } |
71 | | |
72 | | const Mime& |
73 | | DtmfPayloadContents::getStaticType() |
74 | 2 | { |
75 | 2 | static Mime type("application", "dtmf-relay"); |
76 | 2 | return type; |
77 | 2 | } |
78 | | |
79 | | DtmfPayloadContents::DtmfPayload::DtmfPayload(char button, int duration) |
80 | 0 | : mButton(button), |
81 | 0 | mDuration(duration) |
82 | 0 | {} |
83 | | |
84 | | DtmfPayloadContents::DtmfPayload::DtmfPayload(const DtmfPayload& rhs) |
85 | 0 | { |
86 | 0 | *this = rhs; |
87 | 0 | } |
88 | | |
89 | | DtmfPayloadContents::DtmfPayload& |
90 | | DtmfPayloadContents::DtmfPayload::operator=(const DtmfPayload& rhs) |
91 | 0 | { |
92 | 0 | if (this != &rhs) |
93 | 0 | { |
94 | 0 | mButton = rhs.mButton; |
95 | 0 | mDuration = rhs.mDuration; |
96 | 0 | } |
97 | 0 | return *this; |
98 | 0 | } |
99 | | |
100 | | bool |
101 | | DtmfPayloadContents::DtmfPayload::isValidButton(const char c) |
102 | 214 | { |
103 | 214 | static const char permittedChars[] = "ABCD*#"; |
104 | 214 | if(c >= '0' && c <= '9') |
105 | 39 | { |
106 | 39 | return true; |
107 | 39 | } |
108 | 175 | if(strchr(permittedChars, c) != NULL) |
109 | 167 | { |
110 | 167 | return true; |
111 | 167 | } |
112 | 8 | WarningLog(<<"Not a valid DTMF button: " << c); |
113 | 8 | return false; |
114 | 175 | } |
115 | | |
116 | | void |
117 | | DtmfPayloadContents::DtmfPayload::parse(ParseBuffer& pb) |
118 | 6.05k | { |
119 | 6.05k | const char* anchor = pb.skipWhitespace(); |
120 | 6.05k | Data val; |
121 | 6.05k | pb.skipToChars(Symbols::EQUALS); |
122 | 6.05k | pb.data(val, anchor); |
123 | 6.05k | if(!isEqualNoCase(val, "Signal")) |
124 | 5.81k | { |
125 | 5.81k | ErrLog(<<"first key must be Signal, found: " << val); |
126 | 5.81k | throw ParseException("first key must be Signal", pb.getContext(), __FILE__, __LINE__); |
127 | 5.81k | } |
128 | 235 | pb.skipChar(); |
129 | 235 | anchor = pb.skipWhitespace(); |
130 | 235 | pb.skipToOneOf(Symbols::CRLF); |
131 | 235 | pb.data(val, anchor); |
132 | 235 | if(val.size() != 1) |
133 | 20 | { |
134 | 20 | ErrLog(<<"signal string [" << val << "], size = " << val.size()); |
135 | 20 | throw ParseException("Exactly one button character expected in SIP INFO", pb.getContext(), __FILE__, __LINE__); |
136 | 20 | } |
137 | 215 | const char& _button = val[0]; |
138 | 215 | if(!isValidButton(_button)) |
139 | 8 | { |
140 | 8 | throw ParseException("Invalid DTMF button character found", pb.getContext(), __FILE__, __LINE__); |
141 | 8 | } |
142 | 207 | StackLog(<< "Button=" << _button); |
143 | | |
144 | 207 | skipEol(pb); |
145 | 207 | anchor = pb.skipWhitespace(); |
146 | 207 | pb.skipToChars(Symbols::EQUALS); |
147 | 207 | pb.data(val, anchor); |
148 | 207 | if(!isEqualNoCase(val, "Duration")) |
149 | 112 | { |
150 | 112 | ErrLog(<<"second key must be Duration, found: " << val); |
151 | 112 | throw ParseException("second key must be Duration", pb.getContext(), __FILE__, __LINE__); |
152 | 112 | } |
153 | 95 | pb.skipChar(); |
154 | 95 | pb.skipWhitespace(); |
155 | 95 | int _duration = pb.integer(); |
156 | | |
157 | 95 | StackLog(<< "Duration = " << _duration); |
158 | 95 | if(_duration < 20 || _duration > 5000) |
159 | 65 | { |
160 | 65 | ErrLog(<<"Invalid duration: " << _duration); |
161 | 65 | throw ParseException("Invalid duration", pb.getContext(), __FILE__, __LINE__); |
162 | 65 | } |
163 | | |
164 | 30 | mButton = _button; |
165 | 30 | mDuration = _duration; |
166 | 30 | } |
167 | | |
168 | | unsigned short |
169 | | DtmfPayloadContents::DtmfPayload::getEventCode() const |
170 | 0 | { |
171 | 0 | resip_assert(mButton); |
172 | 0 | unsigned short eventCode = 0; |
173 | 0 | if(mButton >= '0' && mButton <= '9') |
174 | 0 | { |
175 | 0 | eventCode = mButton - '0'; |
176 | 0 | } |
177 | 0 | else if(mButton == '*') |
178 | 0 | { |
179 | 0 | eventCode = 10; |
180 | 0 | } |
181 | 0 | else if(mButton == '#') |
182 | 0 | { |
183 | 0 | eventCode = 11; |
184 | 0 | } |
185 | 0 | else if(mButton >= 'A' && mButton <= 'D') |
186 | 0 | { |
187 | 0 | eventCode = 12 + mButton - 'A'; |
188 | 0 | } |
189 | 0 | else |
190 | 0 | { |
191 | 0 | resip_assert(0); // unexpected button, should have been caught by the parser |
192 | 0 | } |
193 | |
|
194 | 0 | return eventCode; |
195 | 0 | } |
196 | | |
197 | | EncodeStream& |
198 | | DtmfPayloadContents::DtmfPayload::encode(EncodeStream& s) const |
199 | 0 | { |
200 | 0 | s << "Signal=" << mButton << Symbols::CRLF; |
201 | 0 | s << "Duration=" << mDuration << Symbols::CRLF; |
202 | 0 | return s; |
203 | 0 | } |
204 | | |
205 | | /* ==================================================================== |
206 | | * |
207 | | * Copyright 2014 Daniel Pocock http://danielpocock.com All rights reserved. |
208 | | * |
209 | | * Redistribution and use in source and binary forms, with or without |
210 | | * modification, are permitted provided that the following conditions |
211 | | * are met: |
212 | | * |
213 | | * 1. Redistributions of source code must retain the above copyright |
214 | | * notice, this list of conditions and the following disclaimer. |
215 | | * |
216 | | * 2. Redistributions in binary form must reproduce the above copyright |
217 | | * notice, this list of conditions and the following disclaimer in |
218 | | * the documentation and/or other materials provided with the |
219 | | * distribution. |
220 | | * |
221 | | * 3. Neither the name of the author(s) nor the names of any contributors |
222 | | * may be used to endorse or promote products derived from this software |
223 | | * without specific prior written permission. |
224 | | * |
225 | | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS "AS IS" AND |
226 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
227 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
228 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE |
229 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
230 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
231 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
232 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
233 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
234 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
235 | | * SUCH DAMAGE. |
236 | | * |
237 | | * ==================================================================== |
238 | | * |
239 | | * |
240 | | */ |
241 | | |