Merge branch 'connectivity-abstraction' to master
[platform/upstream/iotivity.git] / resource / csdk / stack / src / oicgroup.c
1 //******************************************************************
2 //
3 // Copyright 2014 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 // Defining _POSIX_C_SOURCE macro with 200112L (or greater) as value
22 // causes header files to expose definitions
23 // corresponding to the POSIX.1-2001 base
24 // specification (excluding the XSI extension).
25 // For POSIX.1-2001 base specification,
26 // Refer http://pubs.opengroup.org/onlinepubs/009695399/
27 #define _POSIX_C_SOURCE 200112L
28 #include <string.h>
29
30 #include "cJSON.h"
31 #include "ocmalloc.h"
32 #include "oicgroup.h"
33 #include "ocresource.h"
34 #include "occollection.h"
35 #include "logger.h"
36
37 #define TAG PCF("OICGROUP")
38
39 #define DESC_DELIMITER          "\""
40 #define ACTION_DELIMITER        "*"
41 #define ATTR_DELIMITER          "|"
42 #define ATTR_ASSIGN             "="
43
44 // Definitions for operations related to actions
45 #define DO_ACTION               "DoAction"
46 #define GET_ACTIONSET           "GetActionSet"
47 #define ACTIONSET               "ActionSet"
48 #define DELETE_ACTIONSET        "DelActionSet"
49
50 typedef struct aggregatehandleinfo
51 {
52     OCServerRequest *ehRequest;
53     OCDoHandle required;
54     OCResource *collResource;
55
56     struct aggregatehandleinfo *next;
57 } ClientRequestInfo;
58
59 static ClientRequestInfo *clientRequestList = NULL;
60
61 void AddClientRequestInfo(ClientRequestInfo **head, ClientRequestInfo* add)
62 {
63     ClientRequestInfo *tmp = NULL;
64
65     if (*head != NULL)
66     {
67         tmp = *head;
68
69         while (tmp->next)
70         {
71             tmp = tmp->next;
72         }
73         tmp->next = add;
74     }
75     else
76     {
77         *head = add;
78     }
79 }
80
81 ClientRequestInfo* GetClientRequestInfo(ClientRequestInfo *head, OCDoHandle handle)
82 {
83     ClientRequestInfo *tmp = NULL;
84
85     tmp = head;
86
87     if (tmp)
88     {
89         while (tmp)
90         {
91             if (tmp->required == handle)
92             {
93                 break;
94             }
95
96             tmp = tmp->next;
97         }
98
99         return tmp;
100     }
101     return NULL;
102 }
103
104 void RemoveClientRequestInfo(ClientRequestInfo **head, ClientRequestInfo* del)
105 {
106     ClientRequestInfo *tmp = NULL;
107
108     if (*head == del)
109     {
110         *head = (*head)->next;
111     }
112     else
113     {
114         tmp = *head;
115         while (tmp->next && (tmp->next != del))
116         {
117             tmp = tmp->next;
118         }
119         if (tmp->next)
120         {
121             tmp->next = del->next;
122         }
123     }
124 }
125
126 void AddCapability(OCCapability** head, OCCapability* node)
127 {
128     OCCapability *pointer = *head;
129     if (NULL == pointer)
130     {
131         *head = node;
132     }
133     else
134     {
135         while (pointer->next != NULL)
136         {
137             pointer = pointer->next;
138         }
139
140         pointer->next = node;
141     }
142 }
143
144 void AddAction(OCAction** head, OCAction* node)
145 {
146     OCAction *pointer = *head;
147     if (NULL == pointer)
148     {
149         *head = node;
150     }
151     else
152     {
153
154         while (pointer->next != NULL)
155         {
156             pointer = pointer->next;
157         }
158
159         pointer->next = node;
160     }
161 }
162
163 void AddActionSet(OCActionSet **head, OCActionSet* node)
164 {
165     OCActionSet *pointer = *head;
166     if (NULL == pointer)
167     {
168         *head = node;
169     }
170     else
171     {
172
173         while (pointer->next != NULL)
174         {
175             pointer = pointer->next;
176         }
177
178         pointer->next = node;
179     }
180 }
181
182 void DeleteCapability(OCCapability *del)
183 {
184     OCFree(del->capability);
185     del->capability = NULL;
186     OCFree(del->status);
187     del->status = NULL;
188 }
189
190 void DeleteAction(OCAction** action)
191 {
192     OCCapability* pointer = (*action)->head;
193     OCCapability* pDel = NULL;
194
195     while (pointer)
196     {
197         pDel = pointer;
198         pointer = pointer->next;
199
200         DeleteCapability(pDel);
201         pDel->next = NULL;
202     }
203     OCFree((*action)->resourceUri);
204     (*action)->resourceUri = NULL;
205     (*action)->next = NULL;
206 }
207
208 void DeleteActionSet(OCActionSet** actionset)
209 {
210     OCAction* pointer = (*actionset)->head;
211     OCAction* pDel = NULL;
212
213     while (pointer)
214     {
215         pDel = pointer;
216         pointer = pointer->next;
217
218         DeleteAction(&pDel);
219         pDel->next = NULL;
220     }
221
222     OCFree((*actionset)->actionsetName);
223     (*actionset)->head = NULL;
224 }
225
226 OCStackResult FindAndDeleteActionSet(OCResource **resource, const char * actionsetName)
227 {
228     if (*resource != NULL)
229     {
230         OCActionSet *pointer = NULL;
231         OCActionSet *pDel = NULL;
232
233         pointer = (*resource)->actionsetHead;
234
235         if (pointer == NULL)
236         {
237             return OC_STACK_ERROR;
238         }
239         else
240         {
241             if (strcmp(pointer->actionsetName, actionsetName) == 0)
242             {
243                 if (pointer->next != NULL)
244                     (*resource)->actionsetHead = pointer->next;
245                 else
246                     (*resource)->actionsetHead = NULL;
247                 DeleteActionSet(&pointer);
248             }
249             else if (pointer->next != NULL)
250             {
251                 while (pointer)
252                 {
253                     if (pointer->next != NULL)
254                     {
255                         if (strcmp(pointer->next->actionsetName, actionsetName) == 0)
256                         {
257                             pDel = pointer->next;
258                             pointer->next = pointer->next->next;
259
260                             DeleteActionSet(&pDel);
261                         }
262                     }
263                     pointer = pointer->next;
264                 }
265             }
266
267             return OC_STACK_OK;
268         }
269
270     }
271     return OC_STACK_ERROR;
272 }
273
274 OCStackResult DeleteActionSets(OCResource** resource)
275 {
276     OCActionSet *pointer = (*resource)->actionsetHead;
277     OCActionSet *pDel = pointer;
278
279     while (pointer)
280     {
281         pDel = pointer;
282         pointer = pointer->next;
283
284         DeleteActionSet(&pDel);
285         pDel->next = NULL;
286     }
287
288     (*resource)->actionsetHead = NULL;
289     return OC_STACK_OK;
290 }
291
292 OCStackResult GetActionSet(const char *actionName, OCActionSet *head, OCActionSet** actionset)
293 {
294     OCActionSet *pointer = head;
295
296     while (pointer)
297     {
298         if (strcmp(pointer->actionsetName, actionName) == 0)
299         {
300             *actionset = pointer;
301             return OC_STACK_OK;
302         }
303
304         pointer = pointer->next;
305     }
306
307     return OC_STACK_ERROR;
308
309 }
310
311
312 #define OIC_ACTION_PREFIX               "{\"oc\":[{\"rep\":{"
313 #define VARIFY_POINTER_NULL(pointer, result, toExit) \
314     if(pointer == NULL) \
315     {\
316         result = OC_STACK_NO_MEMORY;\
317         goto toExit;\
318     }
319 #define VARIFY_PARAM_NULL(pointer, result, toExit) \
320     if(pointer == NULL)\
321     {\
322         result = OC_STACK_INVALID_PARAM;\
323         goto exit;\
324     }
325
326 OCStackResult ExtractKeyValueFromRequest(char *request, char **key, char **value)
327 {
328     OCStackResult result = OC_STACK_OK;
329     size_t length = 0;
330
331     if(strlen(request) <= strlen(OIC_ACTION_PREFIX))
332     {
333         return OC_STACK_INVALID_PARAM;
334     }
335
336     char* pRequest = (char *)request + strlen(OIC_ACTION_PREFIX);
337     char* iterToken = NULL;
338     char* iterTokenPtr = NULL;
339
340     iterToken = (char *) strtok_r(pRequest, ":", &iterTokenPtr);
341     length = strlen(iterToken) + 1;
342
343     *key = (char *)OCMalloc(length);
344     VARIFY_POINTER_NULL(*key, result, exit);
345
346     strncpy(*key, iterToken + 1, length);
347     ((*key)[ (( length - 1 ) - 2) ]) = '\0';
348
349     iterToken = (char *) strtok_r(NULL, "}", &iterTokenPtr);
350     length = strlen(iterToken) + 1;
351
352     *value = (char *)OCMalloc(length);
353     VARIFY_POINTER_NULL(*key, result, exit);
354
355     strncpy(*value, iterToken + 1, length);
356     ((*value)[ (( length - 1 ) - 2) ]) = '\0';
357 exit:
358     if(result != OC_STACK_OK)
359     {
360         OCFree(*key);
361         OCFree(*value);
362         *key = NULL;
363         *value = NULL;
364     }
365
366     return result;
367 }
368
369 OCStackResult BuildActionSetFromString(OCActionSet **set, char* actiondesc)
370 {
371     OCStackResult result = OC_STACK_OK;
372
373     char *iterToken = NULL, *iterTokenPtr = NULL;
374     char *descIterToken = NULL;
375     char *descIterTokenPtr = NULL;
376     char *attrIterToken = NULL;
377     char *attrIterTokenPtr = NULL;
378     char *desc = NULL;
379     char *attr = NULL;
380     char *key = NULL;
381     char *value = NULL;
382
383     OCAction *action = NULL;
384     OCCapability *capa = NULL;
385
386     OC_LOG(INFO, TAG, PCF("Build ActionSet Instance."));
387
388     *set = (OCActionSet*) OCMalloc(sizeof(OCActionSet));
389     VARIFY_POINTER_NULL(*set, result, exit)
390
391     iterToken = (char *) strtok_r(actiondesc, ACTION_DELIMITER, &iterTokenPtr);
392
393     memset(*set, 0, sizeof(OCActionSet));
394     (*set)->actionsetName = (char *)OCMalloc(sizeof(OCActionSet));
395     VARIFY_POINTER_NULL((*set)->actionsetName, result, exit)
396     VARIFY_PARAM_NULL(iterToken, result, exit)
397     strncpy((*set)->actionsetName, iterToken, strlen(iterToken) + 1);
398
399     OC_LOG_V(INFO, TAG, "ActionSet Name : %s", (*set)->actionsetName);
400
401     iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
402     while(iterToken)
403     {
404         desc = (char *)OCMalloc(strlen(iterToken) + 1);
405         strncpy(desc, iterToken, strlen(iterToken) + 1);
406         descIterToken = (char *) strtok_r(desc, ATTR_DELIMITER, &descIterTokenPtr);
407         while(descIterToken)
408         {
409             attr = (char *)OCMalloc(strlen(descIterToken) + 1);
410             strncpy(attr, descIterToken, strlen(descIterToken) + 1);
411
412             attrIterToken = (char *) strtok_r(attr, ATTR_ASSIGN, &attrIterTokenPtr);
413             key = (char *)OCMalloc(strlen(attrIterToken) + 1);
414             VARIFY_POINTER_NULL(key, result, exit)
415
416             VARIFY_PARAM_NULL(attrIterToken, result, exit)
417             strncpy(key, attrIterToken, strlen(attrIterToken) + 1);
418             attrIterToken = (char *) strtok_r(NULL, ATTR_ASSIGN, &attrIterTokenPtr);
419
420             value = (char *)OCMalloc(strlen(attrIterToken) + 1);
421             VARIFY_POINTER_NULL(value, result, exit)
422             VARIFY_PARAM_NULL(attrIterToken, result, exit)
423             strncpy(value, attrIterToken, strlen(attrIterToken) + 1);
424
425             if(strncmp(key, "uri", sizeof("uri") - 1) == 0)
426             {
427                 OC_LOG(INFO, TAG, PCF("Build OCAction Instance."));
428
429                 action = (OCAction*)OCMalloc(sizeof(OCAction));
430                 VARIFY_POINTER_NULL(action, result, exit)
431                 memset(action, 0, sizeof(OCAction));
432                 action->resourceUri = (char *)OCMalloc(strlen(value) + 1);
433                 VARIFY_POINTER_NULL(action->resourceUri, result, exit)
434                 VARIFY_PARAM_NULL(value, result, exit)
435                 strncpy(action->resourceUri, value, strlen(value) + 1);
436             }
437             else
438             {
439                 if( (key != NULL) && (value != NULL))
440                 {
441                     OC_LOG(INFO, TAG, PCF("Build OCCapability Instance."));
442                     capa = (OCCapability*)OCMalloc(sizeof(OCCapability));
443                     VARIFY_POINTER_NULL(capa, result, exit)
444                     memset(capa, 0, sizeof(OCCapability));
445                     capa->capability = (char *)OCMalloc(strlen(key) + 1);
446                     capa->status = (char *)OCMalloc(strlen(value) + 1);
447
448                     strncpy(capa->capability, key, strlen(key) + 1);
449                     strncpy(capa->status, value, strlen(value) + 1);
450
451                     VARIFY_POINTER_NULL(action, result, exit)
452
453                     AddCapability(&action->head, capa);
454                 }
455             }
456
457             OCFree(key);
458             OCFree(value);
459             OCFree(attr);
460
461             descIterToken = (char *) strtok_r(NULL, ATTR_DELIMITER, &descIterTokenPtr);
462         }
463
464         AddAction(&(*set)->head, action);
465         iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
466         OCFree(desc);
467     }
468
469     return OC_STACK_OK;
470 exit:
471     OCFree(attr);
472     OCFree(desc);
473     OCFree(capa);
474     OCFree(action);
475     OCFree(*set);
476     *set = NULL;
477     return result;
478 }
479
480 OCStackResult BuildStringFromActionSet(OCActionSet* actionset, char** desc)
481 {
482     char temp[1024] = { 0 };
483     uint16_t remaining = sizeof(temp) - 1;
484
485     OCAction *action = actionset->head;
486
487     if (remaining >= strlen(actionset->actionsetName) + (sizeof(ACTION_DELIMITER)-1) )
488     {
489         strncat(temp, actionset->actionsetName, remaining);
490         remaining -= strlen(actionset->actionsetName);
491         strcat(temp, ACTION_DELIMITER);
492         remaining -= (sizeof(ACTION_DELIMITER)-1);
493     }
494     else
495     {
496         return OC_STACK_ERROR;
497     }
498
499     while (action != NULL)
500     {
501         OC_LOG_V(INFO, TAG, "\tURI :: %s\n", action->resourceUri);
502         strcat(temp, "uri=");
503         remaining -= strlen("uri=");
504         strcat(temp, action->resourceUri);
505         remaining -= strlen(action->resourceUri);
506         strcat(temp, ATTR_DELIMITER);
507         remaining--;
508
509         OCCapability *capas = action->head;
510         while (capas != NULL)
511         {
512             OC_LOG_V(INFO, TAG, "\t\t%s = %s\n", capas->capability, capas->status);
513             strcat(temp, capas->capability);
514             remaining -= strlen(capas->capability);
515             strcat(temp, ATTR_ASSIGN);
516             remaining--;
517             strcat(temp, capas->status);
518             remaining -= strlen(capas->capability);
519
520             capas = capas->next;
521             if (capas != NULL)
522             {
523                 strcat(temp, ATTR_DELIMITER);
524             }
525         }
526
527         action = action->next;
528         if (action != NULL)
529         {
530             strcat(temp, ACTION_DELIMITER);
531             remaining--;
532         }
533     }
534
535     *desc = (char *) OCMalloc(1024 - remaining);
536     if(!*desc)
537     {
538         return OC_STACK_NO_MEMORY;
539     }
540
541     strcpy(*desc, temp);
542
543     return OC_STACK_OK;
544 }
545
546 OCStackApplicationResult ActionSetCB(void* context, OCDoHandle handle,
547         OCClientResponse* clientResponse)
548 {
549     OC_LOG(INFO, TAG, PCF("\n\n\tcallback is called\n\n"));
550
551     ClientRequestInfo *info = GetClientRequestInfo(clientRequestList, handle);
552
553     if (info)
554     {
555         uint32_t idx = 0;
556
557         char *responseJson = (char *) OCMalloc(
558                 (unsigned int) (strlen( clientResponse->resJSONPayload) + 1));
559
560         // We need the body of response.
561         // Copy the body from the response
562         strncpy((char *) responseJson, (clientResponse->resJSONPayload
563                 + OC_JSON_PREFIX_LEN), strlen(clientResponse->resJSONPayload) + 1);
564         idx = strlen((char *) responseJson) - OC_JSON_SUFFIX_LEN;
565         // And insert NULL at the end of body.
566         (responseJson[idx]) = 0;
567
568         OCEntityHandlerResponse response = { };
569         response.ehResult = OC_EH_OK;
570         response.payload = responseJson;
571         response.payloadSize = (unsigned int) strlen((char *) responseJson) + 1;
572         response.persistentBufferFlag = 0;
573         response.requestHandle = (OCRequestHandle) info->ehRequest;
574         response.resourceHandle = (OCResourceHandle) info->collResource;
575
576         OCDoResponse(&response);
577
578         RemoveClientRequestInfo(&clientRequestList, info);
579         OCFree(responseJson);
580     }
581
582     return OC_STACK_KEEP_TRANSACTION;
583 }
584
585 void ActionSetCD(void *context)
586 {
587 }
588
589 OCStackResult BuildActionJSON(OCAction* action, char* bufferPtr, uint16_t *remaining)
590 {
591     OCStackResult ret = OC_STACK_ERROR;
592     cJSON *json = NULL;
593     cJSON *body = NULL;
594
595     char *jsonStr = NULL;
596     uint16_t jsonLen = 0;
597
598     OC_LOG(INFO, TAG, PCF("Entering BuildActionJSON"));
599     json = cJSON_CreateObject();
600
601     cJSON_AddItemToObject(json, OC_RSRVD_REPRESENTATION, body = cJSON_CreateObject());
602
603     OCCapability* pointerCapa = action->head;
604     while (pointerCapa)
605     {
606         cJSON_AddStringToObject(body, pointerCapa->capability, pointerCapa->status);
607         pointerCapa = pointerCapa->next;
608     }
609
610     jsonStr = cJSON_PrintUnformatted(json);
611
612     jsonLen = strlen(jsonStr);
613     if (jsonLen < *remaining)
614     {
615         strcat((char*) bufferPtr, jsonStr);
616         *remaining -= jsonLen;
617         bufferPtr += jsonLen;
618         ret = OC_STACK_OK;
619     }
620
621     cJSON_Delete(json);
622     OCFree(jsonStr);
623
624     return ret;
625 }
626
627 uint32_t GetNumOfTargetResource(OCAction *actionset)
628 {
629     uint32_t numOfResource = 0;
630
631     OCAction *pointerAction = actionset;
632
633     while (pointerAction != NULL)
634     {
635         numOfResource++;
636         pointerAction = pointerAction->next;
637     }
638
639     return numOfResource;
640 }
641
642 OCStackResult SendAction(OCDoHandle *handle, const char *targetUri, const char *action)
643 {
644     OCCallbackData cbdata = {  };
645     cbdata.cb = &ActionSetCB;
646     cbdata.cd = &ActionSetCD;
647     cbdata.context = (void *) 0x99;
648
649     return OCDoResource(handle, OC_REST_PUT, targetUri,
650     //temp->rsrcType->resourcetypename,
651             NULL, (char *) action, OC_WIFI, OC_NA_QOS, &cbdata, NULL, 0);
652 }
653
654 OCStackResult BuildCollectionGroupActionJSONResponse(OCMethod method/*OCEntityHandlerFlag flag*/,
655         OCResource *resource, OCEntityHandlerRequest *ehRequest)
656 {
657     OCStackResult stackRet = OC_STACK_ERROR;
658
659     OC_LOG(INFO, TAG, PCF("Group Action is requested."));
660     char *doWhat = NULL;
661     char *details = NULL;
662
663     size_t bufferLength = 0;
664     char buffer[MAX_RESPONSE_LENGTH] = { 0 };
665     char *bufferPtr = NULL;
666
667     bufferPtr = buffer;
668
669     OCResource * collResource = (OCResource *) ehRequest->resource;
670
671     char *jsonResponse;
672
673     stackRet = ExtractKeyValueFromRequest((char *)ehRequest->reqJSONPayload, &doWhat, &details);
674
675     if (stackRet != OC_STACK_OK)
676     {
677         return stackRet;
678     }
679
680     cJSON *json;
681     cJSON *format;
682
683
684     if (method == OC_REST_PUT)
685     {
686         json = cJSON_CreateObject();
687         cJSON_AddStringToObject(json, OC_RSRVD_HREF, resource->uri);
688         cJSON_AddItemToObject(json, OC_RSRVD_REPRESENTATION, format = cJSON_CreateObject());
689
690         OC_LOG(INFO, TAG, PCF("Group Action[PUT]."));
691
692         if(strcmp(doWhat, ACTIONSET) == 0)
693         {
694             OCActionSet *actionSet;
695             BuildActionSetFromString(&actionSet, details);
696
697             if(actionSet != NULL)
698             {
699                 AddActionSet(&resource->actionsetHead, actionSet);
700                 stackRet = OC_STACK_OK;
701             }
702             else
703             {
704                 stackRet = OC_STACK_ERROR;
705             }
706
707         }
708         else if (strncmp(doWhat, DELETE_ACTIONSET, sizeof(DELETE_ACTIONSET)) == 0)
709         {
710             if (FindAndDeleteActionSet(&resource, details) == OC_STACK_OK)
711             {
712                 stackRet = OC_STACK_OK;
713             }
714             else
715             {
716                 stackRet = OC_STACK_ERROR;
717             }
718         }
719
720         jsonResponse = cJSON_Print(json);
721         cJSON_Delete(json);
722
723         strcat((char *) bufferPtr, jsonResponse);
724
725         bufferLength = strlen((const char *) buffer);
726         if (bufferLength > 0)
727         {
728             OCEntityHandlerResponse response = { 0 };
729             response.ehResult = OC_EH_OK;
730             response.payload = buffer;
731             response.payloadSize = bufferLength + 1;
732             response.persistentBufferFlag = 0;
733             response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
734             response.resourceHandle = (OCResourceHandle) collResource;
735             stackRet = OCDoResponse(&response);
736         }
737
738         stackRet = OC_STACK_OK;
739     }
740
741     if (method == OC_REST_POST)
742     {
743         OC_LOG(INFO, TAG, PCF("Group Action[POST]."));
744
745         OCActionSet *actionset = NULL;
746
747         json = cJSON_CreateObject();
748         cJSON_AddStringToObject(json, OC_RSRVD_HREF, resource->uri);
749
750         if (strcmp(doWhat, DO_ACTION) == 0)
751         {
752             if (GetActionSet(details, resource->actionsetHead, &actionset) != OC_STACK_OK)
753             {
754                 OC_LOG(ERROR, TAG, PCF("ERROR: GetActionSet failed"));
755                 stackRet = OC_STACK_ERROR;
756             }
757
758             if (actionset == NULL)
759             {
760                 OC_LOG(ERROR, TAG, PCF("ERROR: Actionset is NULL"));
761                 stackRet = OC_STACK_ERROR;
762             }
763             else
764             {
765
766                 OCAction *pointerAction = actionset->head;
767
768                 uint32_t num = GetNumOfTargetResource(pointerAction);
769
770                 ((OCServerRequest *) ehRequest->requestHandle)->ehResponseHandler =
771                         HandleAggregateResponse;
772                 ((OCServerRequest *) ehRequest->requestHandle)->numResponses = num + 1;
773
774                 while (pointerAction != NULL)
775                 {
776                     char actionDesc[MAX_RESPONSE_LENGTH] = { 0 };
777                     char* actionDescPtr = actionDesc;
778                     uint16_t remaining = MAX_RESPONSE_LENGTH;
779
780                     strncpy((char *) actionDescPtr, (const char *) OC_JSON_PREFIX,
781                         strlen((const char *) OC_JSON_PREFIX) + 1);
782                     BuildActionJSON(pointerAction, actionDescPtr, &remaining);
783                     strncat((char *) actionDescPtr, (const char *) OC_JSON_SUFFIX,
784                         strlen((const char *) OC_JSON_SUFFIX));
785
786                     ClientRequestInfo *info = (ClientRequestInfo *) OCMalloc(
787                             sizeof(ClientRequestInfo));
788                     memset(info, 0, sizeof(ClientRequestInfo));
789
790                     info->collResource = resource;
791                     info->ehRequest = (OCServerRequest *) ehRequest->requestHandle;
792
793                     SendAction(&info->required, pointerAction->resourceUri, actionDescPtr);
794
795                     AddClientRequestInfo(&clientRequestList, info);
796
797                     pointerAction = pointerAction->next;
798                 }
799
800
801                 stackRet = OC_STACK_OK;
802             }
803         }
804         else if (strcmp(doWhat, GET_ACTIONSET) == 0)
805         {
806             char *plainText = NULL;
807             OCActionSet *actionset = NULL;
808
809             cJSON_AddItemToObject(json, OC_RSRVD_REPRESENTATION, format = cJSON_CreateObject());
810             GetActionSet(details, resource->actionsetHead, &actionset);
811             if (actionset != NULL)
812             {
813                 BuildStringFromActionSet(actionset, &plainText);
814
815                 if (plainText != NULL)
816                 {
817                     cJSON_AddStringToObject(format, ACTIONSET, plainText);
818                 }
819
820                 stackRet = OC_STACK_OK;
821             }
822         }
823
824         jsonResponse = cJSON_Print(json);
825         cJSON_Delete(json);
826
827         strcat((char *) bufferPtr, jsonResponse);
828
829         bufferLength = strlen((const char *) buffer);
830         if (bufferLength > 0)
831         {
832             OCEntityHandlerResponse response = {};
833             response.ehResult = OC_EH_OK;
834             response.payload = buffer;
835             response.payloadSize = bufferLength + 1;
836             response.persistentBufferFlag = 0;
837             response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
838             response.resourceHandle = (OCResourceHandle) collResource;
839             stackRet = OCDoResponse(&response);
840         }
841     }
842
843     OCFree(doWhat);
844     OCFree(details);
845
846     return stackRet;
847 }
848