Coverage Report

Created: 2025-10-12 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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