3 Subroutines for dealing with message objects. */
6 * Copyright (c) 1999-2003 Internet Software Consortium.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
38 * To learn more about the Internet Software Consortium, see
39 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
40 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
41 * ``http://www.nominum.com''.
44 #include <omapip/omapip_p.h>
46 OMAPI_OBJECT_ALLOC (omapi_message,
47 omapi_message_object_t, omapi_type_message)
49 omapi_message_object_t *omapi_registered_messages;
51 isc_result_t omapi_message_new (omapi_object_t **o, const char *file, int line)
53 omapi_message_object_t *m;
57 m = (omapi_message_object_t *)0;
58 status = omapi_message_allocate (&m, file, line);
59 if (status != ISC_R_SUCCESS)
62 g = (omapi_object_t *)0;
63 status = omapi_generic_new (&g, file, line);
64 if (status != ISC_R_SUCCESS) {
65 dfree (m, file, line);
68 status = omapi_object_reference (&m -> inner, g, file, line);
69 if (status != ISC_R_SUCCESS) {
70 omapi_object_dereference ((omapi_object_t **)&m, file, line);
71 omapi_object_dereference (&g, file, line);
74 status = omapi_object_reference (&g -> outer,
75 (omapi_object_t *)m, file, line);
77 if (status != ISC_R_SUCCESS) {
78 omapi_object_dereference ((omapi_object_t **)&m, file, line);
79 omapi_object_dereference (&g, file, line);
83 status = omapi_object_reference (o, (omapi_object_t *)m, file, line);
84 omapi_message_dereference (&m, file, line);
85 omapi_object_dereference (&g, file, line);
86 if (status != ISC_R_SUCCESS)
92 isc_result_t omapi_message_set_value (omapi_object_t *h,
94 omapi_data_string_t *name,
95 omapi_typed_data_t *value)
97 omapi_message_object_t *m;
100 if (h -> type != omapi_type_message)
101 return ISC_R_INVALIDARG;
102 m = (omapi_message_object_t *)h;
104 /* Can't set authlen. */
106 /* Can set authenticator, but the value must be typed data. */
107 if (!omapi_ds_strcmp (name, "authenticator")) {
108 if (m -> authenticator)
109 omapi_typed_data_dereference (&m -> authenticator,
111 omapi_typed_data_reference (&m -> authenticator, value, MDL);
112 return ISC_R_SUCCESS;
114 } else if (!omapi_ds_strcmp (name, "object")) {
115 if (value -> type != omapi_datatype_object)
116 return ISC_R_INVALIDARG;
118 omapi_object_dereference (&m -> object, MDL);
119 omapi_object_reference (&m -> object, value -> u.object, MDL);
120 return ISC_R_SUCCESS;
122 } else if (!omapi_ds_strcmp (name, "notify-object")) {
123 if (value -> type != omapi_datatype_object)
124 return ISC_R_INVALIDARG;
125 if (m -> notify_object)
126 omapi_object_dereference (&m -> notify_object, MDL);
127 omapi_object_reference (&m -> notify_object,
128 value -> u.object, MDL);
129 return ISC_R_SUCCESS;
131 /* Can set authid, but it has to be an integer. */
132 } else if (!omapi_ds_strcmp (name, "authid")) {
133 if (value -> type != omapi_datatype_int)
134 return ISC_R_INVALIDARG;
135 m -> authid = value -> u.integer;
136 return ISC_R_SUCCESS;
138 /* Can set op, but it has to be an integer. */
139 } else if (!omapi_ds_strcmp (name, "op")) {
140 if (value -> type != omapi_datatype_int)
141 return ISC_R_INVALIDARG;
142 m -> op = value -> u.integer;
143 return ISC_R_SUCCESS;
145 /* Handle also has to be an integer. */
146 } else if (!omapi_ds_strcmp (name, "handle")) {
147 if (value -> type != omapi_datatype_int)
148 return ISC_R_INVALIDARG;
149 m -> h = value -> u.integer;
150 return ISC_R_SUCCESS;
152 /* Transaction ID has to be an integer. */
153 } else if (!omapi_ds_strcmp (name, "id")) {
154 if (value -> type != omapi_datatype_int)
155 return ISC_R_INVALIDARG;
156 m -> id = value -> u.integer;
157 return ISC_R_SUCCESS;
159 /* Remote transaction ID has to be an integer. */
160 } else if (!omapi_ds_strcmp (name, "rid")) {
161 if (value -> type != omapi_datatype_int)
162 return ISC_R_INVALIDARG;
163 m -> rid = value -> u.integer;
164 return ISC_R_SUCCESS;
167 /* Try to find some inner object that can take the value. */
168 if (h -> inner && h -> inner -> type -> set_value) {
169 status = ((*(h -> inner -> type -> set_value))
170 (h -> inner, id, name, value));
171 if (status == ISC_R_SUCCESS)
175 return ISC_R_NOTFOUND;
178 isc_result_t omapi_message_get_value (omapi_object_t *h,
180 omapi_data_string_t *name,
181 omapi_value_t **value)
183 omapi_message_object_t *m;
184 if (h -> type != omapi_type_message)
185 return ISC_R_INVALIDARG;
186 m = (omapi_message_object_t *)h;
188 /* Look for values that are in the message data structure. */
189 if (!omapi_ds_strcmp (name, "authlen"))
190 return omapi_make_int_value (value, name, (int)m -> authlen,
192 else if (!omapi_ds_strcmp (name, "authenticator")) {
193 if (m -> authenticator)
194 return omapi_make_value (value, name,
195 m -> authenticator, MDL);
197 return ISC_R_NOTFOUND;
198 } else if (!omapi_ds_strcmp (name, "authid")) {
199 return omapi_make_int_value (value,
200 name, (int)m -> authid, MDL);
201 } else if (!omapi_ds_strcmp (name, "op")) {
202 return omapi_make_int_value (value, name, (int)m -> op, MDL);
203 } else if (!omapi_ds_strcmp (name, "handle")) {
204 return omapi_make_int_value (value, name, (int)m -> h, MDL);
205 } else if (!omapi_ds_strcmp (name, "id")) {
206 return omapi_make_int_value (value, name, (int)m -> id, MDL);
207 } else if (!omapi_ds_strcmp (name, "rid")) {
208 return omapi_make_int_value (value, name, (int)m -> rid, MDL);
211 /* See if there's an inner object that has the value. */
212 if (h -> inner && h -> inner -> type -> get_value)
213 return (*(h -> inner -> type -> get_value))
214 (h -> inner, id, name, value);
215 return ISC_R_NOTFOUND;
218 isc_result_t omapi_message_destroy (omapi_object_t *h,
219 const char *file, int line)
223 omapi_message_object_t *m;
224 if (h -> type != omapi_type_message)
225 return ISC_R_INVALIDARG;
226 m = (omapi_message_object_t *)h;
227 if (m -> authenticator) {
228 omapi_typed_data_dereference (&m -> authenticator, file, line);
230 if (!m -> prev && omapi_registered_messages != m)
231 omapi_message_unregister (h);
233 omapi_object_dereference (&m -> id_object, file, line);
235 omapi_object_dereference (&m -> object, file, line);
236 if (m -> notify_object)
237 omapi_object_dereference (&m -> notify_object, file, line);
238 if (m -> protocol_object)
239 omapi_protocol_dereference (&m -> protocol_object, file, line);
240 return ISC_R_SUCCESS;
243 isc_result_t omapi_message_signal_handler (omapi_object_t *h,
244 const char *name, va_list ap)
246 omapi_message_object_t *m;
247 if (h -> type != omapi_type_message)
248 return ISC_R_INVALIDARG;
249 m = (omapi_message_object_t *)h;
251 if (!strcmp (name, "status")) {
252 if (m -> notify_object &&
253 m -> notify_object -> type -> signal_handler)
254 return ((m -> notify_object -> type -> signal_handler))
255 (m -> notify_object, name, ap);
256 else if (m -> object && m -> object -> type -> signal_handler)
257 return ((m -> object -> type -> signal_handler))
258 (m -> object, name, ap);
260 if (h -> inner && h -> inner -> type -> signal_handler)
261 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
263 return ISC_R_NOTFOUND;
266 /* Write all the published values associated with the object through the
267 specified connection. */
269 isc_result_t omapi_message_stuff_values (omapi_object_t *c,
275 if (m -> type != omapi_type_message)
276 return ISC_R_INVALIDARG;
278 if (m -> inner && m -> inner -> type -> stuff_values)
279 return (*(m -> inner -> type -> stuff_values)) (c, id,
281 return ISC_R_SUCCESS;
284 isc_result_t omapi_message_register (omapi_object_t *mo)
286 omapi_message_object_t *m;
288 if (mo -> type != omapi_type_message)
289 return ISC_R_INVALIDARG;
290 m = (omapi_message_object_t *)mo;
292 /* Already registered? */
293 if (m -> prev || m -> next || omapi_registered_messages == m)
294 return ISC_R_INVALIDARG;
296 if (omapi_registered_messages) {
297 omapi_object_reference
298 ((omapi_object_t **)&m -> next,
299 (omapi_object_t *)omapi_registered_messages, MDL);
300 omapi_object_reference
301 ((omapi_object_t **)&omapi_registered_messages -> prev,
302 (omapi_object_t *)m, MDL);
303 omapi_object_dereference
304 ((omapi_object_t **)&omapi_registered_messages, MDL);
306 omapi_object_reference
307 ((omapi_object_t **)&omapi_registered_messages,
308 (omapi_object_t *)m, MDL);
309 return ISC_R_SUCCESS;;
312 isc_result_t omapi_message_unregister (omapi_object_t *mo)
314 omapi_message_object_t *m;
315 omapi_message_object_t *n;
317 if (mo -> type != omapi_type_message)
318 return ISC_R_INVALIDARG;
319 m = (omapi_message_object_t *)mo;
321 /* Not registered? */
322 if (!m -> prev && omapi_registered_messages != m)
323 return ISC_R_INVALIDARG;
325 n = (omapi_message_object_t *)0;
327 omapi_object_reference ((omapi_object_t **)&n,
328 (omapi_object_t *)m -> next, MDL);
329 omapi_object_dereference ((omapi_object_t **)&m -> next, MDL);
330 omapi_object_dereference ((omapi_object_t **)&n -> prev, MDL);
333 omapi_message_object_t *tmp = (omapi_message_object_t *)0;
334 omapi_object_reference ((omapi_object_t **)&tmp,
335 (omapi_object_t *)m -> prev, MDL);
336 omapi_object_dereference ((omapi_object_t **)&m -> prev, MDL);
338 omapi_object_dereference
339 ((omapi_object_t **)&tmp -> next, MDL);
341 omapi_object_reference
342 ((omapi_object_t **)&tmp -> next,
343 (omapi_object_t *)n, MDL);
344 omapi_object_dereference ((omapi_object_t **)&tmp, MDL);
346 omapi_object_dereference
347 ((omapi_object_t **)&omapi_registered_messages, MDL);
349 omapi_object_reference
350 ((omapi_object_t **)&omapi_registered_messages,
351 (omapi_object_t *)n, MDL);
354 omapi_object_dereference ((omapi_object_t **)&n, MDL);
355 return ISC_R_SUCCESS;
358 #ifdef DEBUG_PROTOCOL
359 static const char *omapi_message_op_name(int op) {
361 case OMAPI_OP_OPEN: return "OMAPI_OP_OPEN";
362 case OMAPI_OP_REFRESH: return "OMAPI_OP_REFRESH";
363 case OMAPI_OP_UPDATE: return "OMAPI_OP_UPDATE";
364 case OMAPI_OP_STATUS: return "OMAPI_OP_STATUS";
365 case OMAPI_OP_DELETE: return "OMAPI_OP_DELETE";
366 case OMAPI_OP_NOTIFY: return "OMAPI_OP_NOTIFY";
367 default: return "(unknown op)";
373 omapi_message_process_internal (omapi_object_t *, omapi_object_t *);
375 isc_result_t omapi_message_process (omapi_object_t *mo, omapi_object_t *po)
378 #if defined (DEBUG_MEMORY_LEAKAGE)
379 unsigned long previous_outstanding = dmalloc_outstanding;
382 status = omapi_message_process_internal (mo, po);
384 #if defined (DEBUG_MEMORY_LEAKAGE) && 0
385 log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
387 dmalloc_outstanding - previous_outstanding,
388 dmalloc_outstanding, dmalloc_longterm);
390 #if defined (DEBUG_MEMORY_LEAKAGE) && 0
391 dmalloc_dump_outstanding ();
393 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY) && 0
401 omapi_message_process_internal (omapi_object_t *mo, omapi_object_t *po)
403 omapi_message_object_t *message, *m;
404 omapi_object_t *object = (omapi_object_t *)0;
405 omapi_value_t *tv = (omapi_value_t *)0;
406 unsigned long create, update, exclusive;
408 isc_result_t status, waitstatus;
409 omapi_object_type_t *type;
411 if (mo -> type != omapi_type_message)
412 return ISC_R_INVALIDARG;
413 message = (omapi_message_object_t *)mo;
415 #ifdef DEBUG_PROTOCOL
416 log_debug ("omapi_message_process(): "
417 "op=%s handle=%#x id=%#x rid=%#x",
418 omapi_message_op_name (message -> op),
419 message -> h, message -> id, message -> rid);
422 if (message -> rid) {
423 for (m = omapi_registered_messages; m; m = m -> next)
424 if (m -> id == message -> rid)
426 /* If we don't have a real message corresponding to
427 the message ID to which this message claims it is a
428 response, something's fishy. */
430 return ISC_R_NOTFOUND;
431 /* The authenticator on responses must match the initial
433 if (message -> authid != m -> authid)
434 return ISC_R_NOTFOUND;
436 m = (omapi_message_object_t *)0;
438 /* All messages must have an authenticator, with the exception
439 of messages that are opening a new authenticator. */
440 if (omapi_protocol_authenticated (po) &&
441 !message -> id_object &&
442 message -> op != OMAPI_OP_OPEN) {
443 return omapi_protocol_send_status
444 (po, message -> id_object, ISC_R_NOKEYS,
445 message -> id, "No authenticator on message");
449 switch (message -> op) {
452 return omapi_protocol_send_status
453 (po, message -> id_object, ISC_R_INVALIDARG,
454 message -> id, "OPEN can't be a response");
457 /* Get the type of the requested object, if one was
459 status = omapi_get_value_str (mo, message -> id_object,
461 if (status == ISC_R_SUCCESS &&
462 (tv -> value -> type == omapi_datatype_data ||
463 tv -> value -> type == omapi_datatype_string)) {
464 for (type = omapi_object_types;
465 type; type = type -> next)
466 if (!omapi_td_strcmp (tv -> value,
470 type = (omapi_object_type_t *)0;
472 omapi_value_dereference (&tv, MDL);
474 /* If this object had no authenticator, the requested object
475 must be an authenticator object. */
476 if (omapi_protocol_authenticated (po) &&
477 !message -> id_object &&
478 type != omapi_type_auth_key) {
479 return omapi_protocol_send_status
480 (po, message -> id_object, ISC_R_NOKEYS,
481 message -> id, "No authenticator on message");
484 /* Get the create flag. */
485 status = omapi_get_value_str (mo, message -> id_object,
487 if (status == ISC_R_SUCCESS) {
488 status = omapi_get_int_value (&create, tv -> value);
489 omapi_value_dereference (&tv, MDL);
490 if (status != ISC_R_SUCCESS) {
491 return omapi_protocol_send_status
492 (po, message -> id_object,
493 status, message -> id,
494 "invalid create flag value");
499 /* Get the update flag. */
500 status = omapi_get_value_str (mo, message -> id_object,
502 if (status == ISC_R_SUCCESS) {
503 status = omapi_get_int_value (&update, tv -> value);
504 omapi_value_dereference (&tv, MDL);
505 if (status != ISC_R_SUCCESS) {
506 return omapi_protocol_send_status
507 (po, message -> id_object,
508 status, message -> id,
509 "invalid update flag value");
514 /* Get the exclusive flag. */
515 status = omapi_get_value_str (mo, message -> id_object,
517 if (status == ISC_R_SUCCESS) {
518 status = omapi_get_int_value (&exclusive, tv -> value);
519 omapi_value_dereference (&tv, MDL);
520 if (status != ISC_R_SUCCESS) {
521 return omapi_protocol_send_status
522 (po, message -> id_object,
523 status, message -> id,
524 "invalid exclusive flag value");
529 /* If we weren't given a type, look the object up with
533 return omapi_protocol_send_status
534 (po, message -> id_object,
537 "type required on create");
542 /* If the type doesn't provide a lookup method, we can't
543 look up the object. */
544 if (!type -> lookup) {
545 return omapi_protocol_send_status
546 (po, message -> id_object,
547 ISC_R_NOTIMPLEMENTED, message -> id,
548 "unsearchable object type");
551 status = (*(type -> lookup)) (&object, message -> id_object,
554 if (status != ISC_R_SUCCESS &&
555 status != ISC_R_NOTFOUND &&
556 status != ISC_R_NOKEYS) {
557 return omapi_protocol_send_status
558 (po, message -> id_object,
559 status, message -> id,
560 "object lookup failed");
563 /* If we didn't find the object and we aren't supposed to
564 create it, return an error. */
565 if (status == ISC_R_NOTFOUND && !create) {
566 return omapi_protocol_send_status
567 (po, message -> id_object,
568 ISC_R_NOTFOUND, message -> id,
569 "no object matches specification");
572 /* If we found an object, we're supposed to be creating an
573 object, and we're not supposed to have found an object,
575 if (status == ISC_R_SUCCESS && create && exclusive) {
576 omapi_object_dereference (&object, MDL);
577 return omapi_protocol_send_status
578 (po, message -> id_object,
579 ISC_R_EXISTS, message -> id,
580 "specified object already exists");
583 /* If we're creating the object, do it now. */
585 status = omapi_object_create (&object,
586 message -> id_object,
588 if (status != ISC_R_SUCCESS) {
589 return omapi_protocol_send_status
590 (po, message -> id_object,
591 status, message -> id,
592 "can't create new object");
596 /* If we're updating it, do so now. */
597 if (create || update) {
598 /* This check does not belong here. */
599 if (object -> type == omapi_type_auth_key) {
600 omapi_object_dereference (&object, MDL);
601 return omapi_protocol_send_status
602 (po, message -> id_object,
603 status, message -> id,
604 "can't update object");
607 status = omapi_object_update (object,
608 message -> id_object,
611 if (status != ISC_R_SUCCESS) {
612 omapi_object_dereference (&object, MDL);
613 return omapi_protocol_send_status
614 (po, message -> id_object,
615 status, message -> id,
616 "can't update object");
620 /* If this is an authenticator object, add it to the active
621 set for the connection. */
622 if (object -> type == omapi_type_auth_key) {
623 omapi_handle_t handle;
624 status = omapi_object_handle (&handle, object);
625 if (status != ISC_R_SUCCESS) {
626 omapi_object_dereference (&object, MDL);
627 return omapi_protocol_send_status
628 (po, message -> id_object,
629 status, message -> id,
630 "can't select authenticator");
633 status = omapi_protocol_add_auth (po, object, handle);
634 if (status != ISC_R_SUCCESS) {
635 omapi_object_dereference (&object, MDL);
636 return omapi_protocol_send_status
637 (po, message -> id_object,
638 status, message -> id,
639 "can't select authenticator");
643 /* Now send the new contents of the object back in
647 case OMAPI_OP_REFRESH:
649 status = omapi_handle_lookup (&object, message -> h);
650 if (status != ISC_R_SUCCESS) {
651 return omapi_protocol_send_status
652 (po, message -> id_object,
653 status, message -> id,
654 "no matching handle");
657 status = omapi_protocol_send_update (po, message -> id_object,
658 message -> id, object);
659 omapi_object_dereference (&object, MDL);
662 case OMAPI_OP_UPDATE:
663 if (m && m -> object) {
664 omapi_object_reference (&object, m -> object, MDL);
666 status = omapi_handle_lookup (&object, message -> h);
667 if (status != ISC_R_SUCCESS) {
668 return omapi_protocol_send_status
669 (po, message -> id_object,
670 status, message -> id,
671 "no matching handle");
675 if (object -> type == omapi_type_auth_key ||
677 object -> inner -> type == omapi_type_auth_key)) {
679 omapi_object_dereference (&object, MDL);
680 return omapi_protocol_send_status
681 (po, message -> id_object,
682 status, message -> id,
683 "cannot update authenticator");
686 status = omapi_protocol_add_auth (po, object,
689 status = omapi_object_update (object,
690 message -> id_object,
694 if (status != ISC_R_SUCCESS) {
695 omapi_object_dereference (&object, MDL);
697 return omapi_protocol_send_status
698 (po, message -> id_object,
699 status, message -> id,
700 "can't update object");
702 omapi_signal ((omapi_object_t *)m,
704 (omapi_typed_data_t *)0);
705 return ISC_R_SUCCESS;
708 status = omapi_protocol_send_status
709 (po, message -> id_object, ISC_R_SUCCESS,
710 message -> id, (char *)0);
712 omapi_signal ((omapi_object_t *)m,
713 "status", ISC_R_SUCCESS,
714 (omapi_typed_data_t *)0);
715 omapi_message_unregister ((omapi_object_t *)m);
718 omapi_object_dereference (&object, MDL);
722 case OMAPI_OP_NOTIFY:
723 return omapi_protocol_send_status
724 (po, message -> id_object, ISC_R_NOTIMPLEMENTED,
725 message -> id, "notify not implemented yet");
727 case OMAPI_OP_STATUS:
728 /* The return status of a request. */
730 return ISC_R_UNEXPECTED;
732 /* Get the wait status. */
733 status = omapi_get_value_str (mo, message -> id_object,
735 if (status == ISC_R_SUCCESS) {
736 status = omapi_get_int_value (&wsi, tv -> value);
738 omapi_value_dereference (&tv, MDL);
739 if (status != ISC_R_SUCCESS)
740 waitstatus = ISC_R_UNEXPECTED;
742 waitstatus = ISC_R_UNEXPECTED;
744 status = omapi_get_value_str (mo, message -> id_object,
746 omapi_signal ((omapi_object_t *)m, "status", waitstatus, tv);
747 if (status == ISC_R_SUCCESS)
748 omapi_value_dereference (&tv, MDL);
750 omapi_message_unregister((omapi_object_t *)m);
752 return ISC_R_SUCCESS;
754 case OMAPI_OP_DELETE:
755 status = omapi_handle_lookup (&object, message -> h);
756 if (status != ISC_R_SUCCESS) {
757 return omapi_protocol_send_status
758 (po, message -> id_object,
759 status, message -> id,
760 "no matching handle");
763 if (!object -> type -> remove)
764 return omapi_protocol_send_status
765 (po, message -> id_object,
766 ISC_R_NOTIMPLEMENTED, message -> id,
767 "no remove method for object");
769 status = (*(object -> type -> remove)) (object,
770 message -> id_object);
771 omapi_object_dereference (&object, MDL);
773 return omapi_protocol_send_status (po, message -> id_object,
774 status, message -> id,
777 return ISC_R_NOTIMPLEMENTED;