Coverage Report

Created: 2025-11-16 06:32

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
5.87k
   : Contents(hfv, contentTypes)
35
5.87k
{
36
5.87k
}
37
38
DtmfPayloadContents::~DtmfPayloadContents()
39
5.87k
{
40
5.87k
}
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
5.87k
{
62
5.87k
   mDtmfPayload.parse(pb);
63
5.87k
}
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
196
{
103
196
   static const char permittedChars[] = "ABCD*#";
104
196
   if(c >= '0' && c <= '9')
105
26
   {
106
26
      return true;
107
26
   }
108
170
   if(strchr(permittedChars, c) != NULL)
109
160
   {
110
160
      return true;
111
160
   }
112
10
   WarningLog(<<"Not a valid DTMF button: " << c);
113
10
   return false;
114
170
}
115
116
void
117
DtmfPayloadContents::DtmfPayload::parse(ParseBuffer& pb)
118
5.87k
{
119
5.87k
   const char* anchor = pb.skipWhitespace();
120
5.87k
   Data val;
121
5.87k
   pb.skipToChars(Symbols::EQUALS);
122
5.87k
   pb.data(val, anchor);
123
5.87k
   if(!isEqualNoCase(val, "Signal"))
124
5.66k
   {
125
5.66k
      ErrLog(<<"first key must be Signal, found: " << val);
126
5.66k
      throw ParseException("first key must be Signal", pb.getContext(), __FILE__, __LINE__);
127
5.66k
   }
128
214
   pb.skipChar();
129
214
   anchor = pb.skipWhitespace();
130
214
   pb.skipToOneOf(Symbols::CRLF);
131
214
   pb.data(val, anchor);
132
214
   if(val.size() != 1)
133
17
   {
134
17
      ErrLog(<<"signal string [" << val << "], size = " << val.size());
135
17
      throw ParseException("Exactly one button character expected in SIP INFO", pb.getContext(), __FILE__, __LINE__);
136
17
   }
137
197
   const char& _button = val[0];
138
197
   if(!isValidButton(_button))
139
10
   {
140
10
      throw ParseException("Invalid DTMF button character found", pb.getContext(), __FILE__, __LINE__);
141
10
   }
142
187
   StackLog(<< "Button=" << _button);
143
144
187
   skipEol(pb);
145
187
   anchor = pb.skipWhitespace();
146
187
   pb.skipToChars(Symbols::EQUALS);
147
187
   pb.data(val, anchor);
148
187
   if(!isEqualNoCase(val, "Duration"))
149
101
   {
150
101
      ErrLog(<<"second key must be Duration, found: " << val);
151
101
      throw ParseException("second key must be Duration", pb.getContext(), __FILE__, __LINE__);
152
101
   }
153
86
   pb.skipChar();
154
86
   pb.skipWhitespace();
155
86
   int _duration = pb.integer();
156
157
86
   StackLog(<< "Duration = " << _duration);
158
86
   if(_duration < 20 || _duration > 5000)
159
58
   {
160
58
      ErrLog(<<"Invalid duration: " << _duration);
161
58
      throw ParseException("Invalid duration", pb.getContext(), __FILE__, __LINE__);
162
58
   }
163
164
28
   mButton = _button;
165
28
   mDuration = _duration;
166
28
}
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