1 /*
2 error_info.c
3 Copyright (C) 2016 Belledonne Communications SARL
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #include "linphone/core.h"
21 #include "private.h"
22
23 BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneErrorInfo);
24
25
26
27 static void linphone_error_info_reset(LinphoneErrorInfo *ei);
28
error_info_destroy(LinphoneErrorInfo * ei)29 static void error_info_destroy(LinphoneErrorInfo *ei){
30 linphone_error_info_reset(ei);
31 }
32
error_info_clone(LinphoneErrorInfo * ei,const LinphoneErrorInfo * other)33 static void error_info_clone(LinphoneErrorInfo *ei, const LinphoneErrorInfo *other){
34 linphone_error_info_set_reason(ei, linphone_error_info_get_reason(other));
35 ei->protocol = bctbx_strdup(other->protocol);
36 ei->phrase = bctbx_strdup(other->phrase);
37 ei->warnings = bctbx_strdup(other->warnings);
38 ei->full_string = bctbx_strdup(other->full_string);
39 ei->protocol_code = other->protocol_code;
40 }
41
42 BELLE_SIP_INSTANCIATE_VPTR(LinphoneErrorInfo, belle_sip_object_t,
43 error_info_destroy, // destroy
44 error_info_clone, // clone
45 NULL, // Marshall
46 FALSE
47 );
48
linphone_error_info_new(void)49 LinphoneErrorInfo *linphone_error_info_new(void){
50 LinphoneErrorInfo *ei = belle_sip_object_new(LinphoneErrorInfo);
51 return ei;
52 }
53
linphone_error_info_ref(LinphoneErrorInfo * ei)54 LinphoneErrorInfo* linphone_error_info_ref ( LinphoneErrorInfo* ei ) {
55 return (LinphoneErrorInfo*) belle_sip_object_ref(ei);
56 }
57
linphone_error_info_unref(LinphoneErrorInfo * ei)58 void linphone_error_info_unref ( LinphoneErrorInfo* ei ) {
59 belle_sip_object_unref(ei);
60 }
61
62
linphone_reason_to_string(LinphoneReason err)63 const char *linphone_reason_to_string(LinphoneReason err){
64 switch(err) {
65 case LinphoneReasonNone:
66 return "No error";
67 case LinphoneReasonNoResponse:
68 return "No response";
69 case LinphoneReasonForbidden:
70 return "Bad credentials";
71 case LinphoneReasonDeclined:
72 return "Call declined";
73 case LinphoneReasonNotFound:
74 return "User not found";
75 case LinphoneReasonNotAnswered:
76 return "Not answered";
77 case LinphoneReasonBusy:
78 return "Busy";
79 case LinphoneReasonMedia:
80 return "Incompatible media capabilities";
81 case LinphoneReasonIOError:
82 return "IO error";
83 case LinphoneReasonDoNotDisturb:
84 return "Do not disturb";
85 case LinphoneReasonUnauthorized:
86 return "Unauthorized";
87 case LinphoneReasonNotAcceptable:
88 return "Not acceptable here";
89 case LinphoneReasonNoMatch:
90 return "No match";
91 case LinphoneReasonMovedPermanently:
92 return "Moved permanently";
93 case LinphoneReasonGone:
94 return "Gone";
95 case LinphoneReasonTemporarilyUnavailable:
96 return "Temporarily unavailable";
97 case LinphoneReasonAddressIncomplete:
98 return "Address incomplete";
99 case LinphoneReasonNotImplemented:
100 return "Not implemented";
101 case LinphoneReasonBadGateway:
102 return "Bad gateway";
103 case LinphoneReasonServerTimeout:
104 return "Server timeout";
105 case LinphoneReasonUnknown:
106 return "Unknown error";
107 }
108 return "unknown error";
109 }
110
111 typedef struct _error_code_reason_map {
112 int error_code;
113 LinphoneReason reason;
114 } error_code_reason_map_t;
115
116 static const error_code_reason_map_t error_code_reason_map[] = {
117 { 200, LinphoneReasonNone },
118 { 301, LinphoneReasonMovedPermanently },
119 { 400, LinphoneReasonUnknown },
120 { 401, LinphoneReasonUnauthorized },
121 { 403, LinphoneReasonForbidden },
122 { 404, LinphoneReasonNotFound },
123 { 410, LinphoneReasonGone },
124 { 415, LinphoneReasonUnsupportedContent },
125 { 480, LinphoneReasonTemporarilyUnavailable },
126 { 481, LinphoneReasonNoMatch },
127 { 484, LinphoneReasonAddressIncomplete },
128 { 486, LinphoneReasonBusy },
129 { 488, LinphoneReasonNotAcceptable },
130 { 501, LinphoneReasonNotImplemented },
131 { 502, LinphoneReasonBadGateway },
132 { 503, LinphoneReasonIOError },
133 { 504, LinphoneReasonServerTimeout },
134 { 600, LinphoneReasonDoNotDisturb },
135 { 603, LinphoneReasonDeclined }
136 };
137
linphone_error_code_to_reason(int err)138 LinphoneReason linphone_error_code_to_reason(int err) {
139 size_t i;
140 for (i = 0; i < (sizeof(error_code_reason_map) / sizeof(error_code_reason_map[0])); i++) {
141 if (error_code_reason_map[i].error_code == err) return error_code_reason_map[i].reason;
142 }
143 return LinphoneReasonUnknown;
144 }
145
linphone_reason_to_error_code(LinphoneReason reason)146 int linphone_reason_to_error_code(LinphoneReason reason) {
147 size_t i;
148 for (i = 0; i < (sizeof(error_code_reason_map) / sizeof(error_code_reason_map[0])); i++) {
149 if (error_code_reason_map[i].reason == reason) return error_code_reason_map[i].error_code;
150 }
151 return 400;
152 }
153
linphone_error_info_reset(LinphoneErrorInfo * ei)154 static void linphone_error_info_reset(LinphoneErrorInfo *ei){
155 ei->reason = LinphoneReasonNone;
156 STRING_RESET(ei->protocol);
157 STRING_RESET(ei->phrase);
158 STRING_RESET(ei->full_string);
159 STRING_RESET(ei->warnings);
160 ei->protocol_code = 0;
161 if (ei->sub_ei) {
162 linphone_error_info_unref(ei->sub_ei);
163 ei->sub_ei = NULL;
164 }
165 }
166
linphone_error_info_from_sal(LinphoneErrorInfo * ei,const SalErrorInfo * sei)167 void linphone_error_info_from_sal(LinphoneErrorInfo *ei, const SalErrorInfo *sei){
168 ei->reason = linphone_reason_from_sal(sei->reason);
169 ei->phrase = bctbx_strdup(sei->status_string);
170 ei->full_string = bctbx_strdup(sei->full_string);
171 ei->warnings = bctbx_strdup(sei->warnings);
172 ei->protocol_code = sei->protocol_code;
173 ei->protocol = bctbx_strdup(sei->protocol);
174 }
175
176 /* If a reason header is provided (in reason_ei), then create a sub LinphoneErrorInfo attached to the first one, unless the reason header
177 is in the request, in which case no primary error is given.*/
linphone_error_info_from_sal_reason_ei(LinphoneErrorInfo * ei,const SalErrorInfo * reason_ei)178 void linphone_error_info_from_sal_reason_ei(LinphoneErrorInfo *ei, const SalErrorInfo *reason_ei){
179 if (ei->reason == LinphoneReasonNone){
180 /*no primary error given*/
181 linphone_error_info_reset(ei);
182 linphone_error_info_from_sal(ei, reason_ei);
183 return;
184 }
185
186 if (ei->sub_ei){
187 if (reason_ei->reason == SalReasonNone){
188 linphone_error_info_unref(ei->sub_ei);
189 ei->sub_ei = NULL;
190 }
191 }else{
192 if (reason_ei->reason != SalReasonNone){
193 ei->sub_ei = linphone_error_info_new();
194 }
195 }
196 if (reason_ei->reason != SalReasonNone){
197 linphone_error_info_from_sal(ei->sub_ei, reason_ei);
198 }
199 }
200
linphone_error_info_from_sal_op(LinphoneErrorInfo * ei,const SalOp * op)201 void linphone_error_info_from_sal_op(LinphoneErrorInfo *ei, const SalOp *op){
202 if (op==NULL) {
203 /*leave previous values in LinphoneErrorInfo, the op may have been released already.*/
204 return;
205 }else{
206 const SalErrorInfo *sei;
207 linphone_error_info_reset(ei);
208 sei = sal_op_get_error_info(op);
209 linphone_error_info_from_sal(ei, sei);
210 sei = sal_op_get_reason_error_info(op);
211 linphone_error_info_from_sal_reason_ei(ei, sei);
212 }
213 }
214
linphone_error_info_fields_to_sal(const LinphoneErrorInfo * ei,SalErrorInfo * sei)215 void linphone_error_info_fields_to_sal(const LinphoneErrorInfo* ei, SalErrorInfo* sei){
216 sei->reason = linphone_reason_to_sal(linphone_error_info_get_reason(ei));
217 sei->status_string = bctbx_strdup(ei->phrase);
218 sei->full_string = bctbx_strdup(ei->full_string);
219 sei->warnings = bctbx_strdup(ei->warnings);
220 sei->protocol_code = ei->protocol_code;
221 sei->protocol = bctbx_strdup(ei->protocol);
222 }
223
linphone_error_info_to_sal(const LinphoneErrorInfo * ei,SalErrorInfo * sei)224 void linphone_error_info_to_sal(const LinphoneErrorInfo* ei, SalErrorInfo* sei){
225
226 linphone_error_info_fields_to_sal(ei, sei);
227 if (ei->sub_ei !=NULL) {
228
229 linphone_error_info_to_sal(ei->sub_ei, sei->sub_sei);
230 }
231 }
232
233
linphone_error_info_set(LinphoneErrorInfo * ei,const char * protocol,LinphoneReason reason,int code,const char * status_string,const char * warning)234 void linphone_error_info_set(LinphoneErrorInfo *ei, const char *protocol, LinphoneReason reason, int code, const char *status_string, const char *warning){
235 linphone_error_info_reset(ei);
236 ei->reason = reason;
237 ei->protocol_code = code;
238 ei->protocol = bctbx_strdup(protocol ? protocol : "SIP");
239 ei->phrase = bctbx_strdup(status_string);
240 ei->warnings = bctbx_strdup(warning);
241 }
242
243
linphone_error_info_get_reason(const LinphoneErrorInfo * ei)244 LinphoneReason linphone_error_info_get_reason(const LinphoneErrorInfo *ei) {
245 return ei->reason;
246 }
247
linphone_error_info_get_protocol(const LinphoneErrorInfo * ei)248 const char *linphone_error_info_get_protocol(const LinphoneErrorInfo *ei){
249 return ei->protocol;
250 }
251
linphone_error_info_get_phrase(const LinphoneErrorInfo * ei)252 const char *linphone_error_info_get_phrase(const LinphoneErrorInfo *ei) {
253 return ei->phrase;
254 }
255
256 /*deprecated, kept for binary compatibility*/
linphone_error_info_get_details(const LinphoneErrorInfo * ei)257 const char *linphone_error_info_get_details(const LinphoneErrorInfo *ei){
258 return linphone_error_info_get_warnings(ei);
259 }
260
linphone_error_info_get_warnings(const LinphoneErrorInfo * ei)261 const char *linphone_error_info_get_warnings(const LinphoneErrorInfo *ei) {
262 return ei->warnings;
263 }
264
linphone_error_info_get_protocol_code(const LinphoneErrorInfo * ei)265 int linphone_error_info_get_protocol_code(const LinphoneErrorInfo *ei) {
266 return ei->protocol_code;
267 }
268
linphone_error_info_get_sub_error_info(const LinphoneErrorInfo * ei)269 LinphoneErrorInfo * linphone_error_info_get_sub_error_info(const LinphoneErrorInfo *ei){
270 return ei->sub_ei;
271 }
272
linphone_error_info_set_reason(LinphoneErrorInfo * ei,LinphoneReason reason)273 void linphone_error_info_set_reason(LinphoneErrorInfo *ei, LinphoneReason reason){
274 ei->reason = reason;
275 }
276
linphone_error_info_set_protocol(LinphoneErrorInfo * ei,const char * proto)277 void linphone_error_info_set_protocol(LinphoneErrorInfo *ei, const char *proto){
278 STRING_SET(ei->protocol, proto);
279 }
280
linphone_error_info_set_protocol_code(LinphoneErrorInfo * ei,int code)281 void linphone_error_info_set_protocol_code(LinphoneErrorInfo *ei, int code){
282 ei->protocol_code = code;
283 }
284
linphone_error_info_set_phrase(LinphoneErrorInfo * ei,const char * phrase)285 void linphone_error_info_set_phrase(LinphoneErrorInfo *ei, const char *phrase){
286 STRING_SET(ei->phrase, phrase);
287 }
288
linphone_error_info_set_warnings(LinphoneErrorInfo * ei,const char * warnings)289 void linphone_error_info_set_warnings(LinphoneErrorInfo *ei, const char *warnings){
290 STRING_SET(ei->warnings, warnings);
291 }
292
linphone_error_info_set_sub_error_info(LinphoneErrorInfo * ei,LinphoneErrorInfo * appended_ei)293 void linphone_error_info_set_sub_error_info(LinphoneErrorInfo *ei, LinphoneErrorInfo *appended_ei){
294 if (appended_ei != NULL){
295 linphone_error_info_ref(appended_ei);
296 }
297 if (ei->sub_ei){
298 linphone_error_info_unref(ei->sub_ei);
299 }
300 ei->sub_ei = appended_ei;
301 }
302