#include "connor_cad.h" #include "k_util.h" #include #include #pragma comment(lib, "ws2_32.lib") #define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING #include #pragma warning(disable:4996) #define ITK_err 919011 #define PROP_LOCATION_ITEM "item" #define PROP_LOCATION_REV "rev" #define PROP_LOCATION_ITEMMASTER "itemmaster" #define PROP_LOCATION_REVMASTER "revmaster" typedef struct { string prop_location; string prop_name; } Prop_Config; typedef struct { string rev_type; string title_block_names; map prop_config_map; } Sign_Config; int ParseConfigFromPreference(map& sign_config_map) { int ifail = ITK_ok, pref_cnt = 0; char** pref_values = NULL; ITKCALL(ifail = PREF_ask_char_values(PREF_SIGNATURE, &pref_cnt, &pref_values)); if (ifail != ITK_ok) { goto end; } for (int i = 0; i < pref_cnt; i++) { string value, rev_type, title_block_names; map prop_config_map; vector prop_configs; value.assign(pref_values[i]); printf("1111\n"); int ind = value.find(":"); if (ind == string::npos || ind == 0) { continue; } printf("2222\n"); rev_type = value.substr(0, ind); printf("rev_type:%s\n", rev_type.c_str()); if (sign_config_map.count(rev_type) > 0) { continue; } printf("3333\n"); value = value.substr(ind + 1); ind = value.find(":"); if (ind == string::npos || ind == 0) { continue; } printf("4444\n"); title_block_names = value.substr(0, ind); value = value.substr(ind + 1); Splits(value, ";", prop_configs); int size = prop_configs.size(); for (int j = 0; j < size; j++) { string cad_prop_name, prop_location, prop_name; value = prop_configs[j]; ind = value.find("="); if (ind == string::npos || ind == 0) { continue; } cad_prop_name = value.substr(0, ind); if (prop_config_map.count(cad_prop_name) > 0) { continue; } value = value.substr(ind + 1); ind = value.find("."); if (ind == string::npos || ind == 0) { continue; } prop_location = value.substr(0, ind); prop_name = value.substr(ind + 1); if (prop_name.empty()) { continue; } transform(prop_location.begin(), prop_location.end(), prop_location.begin(), ::tolower); if (prop_location._Equal(PROP_LOCATION_ITEM) || prop_location._Equal(PROP_LOCATION_REV) || prop_location._Equal(PROP_LOCATION_ITEMMASTER) || prop_location._Equal(PROP_LOCATION_REVMASTER)) { Prop_Config prop_config; prop_config.prop_location = prop_location; prop_config.prop_name = prop_name; prop_config_map.insert(make_pair(cad_prop_name, prop_config)); } } if (prop_config_map.size() > 0) { Sign_Config sign_config; sign_config.rev_type = rev_type; sign_config.title_block_names = title_block_names; sign_config.prop_config_map = prop_config_map; sign_config_map.insert(make_pair(rev_type, sign_config)); printf("次数%d\n", i); } } if (sign_config_map.size() < 1) { ITKCALL(ifail = EMH_store_error_s2(EMH_severity_error, ITK_err, ("首选项配置错误"), PREF_SIGNATURE)); ifail = ITK_err; } end: DOFREE(pref_values); return ifail; } int ReadSignInfo(tag_t rev_tag, Sign_Config sign_config, string& info) { int ifail = ITK_ok; map::iterator iter; char* prop_value = NULL, * object_string = NULL; tag_t item_tag = NULLTAG, item_master_tag = NULLTAG, rev_master_tag = NULLTAG; ITKCALL(ifail = AOM_refresh(rev_tag, false)); if (ifail != ITK_ok) { goto end; } ITKCALL(ifail = AOM_ask_value_string(rev_tag, "object_string", &object_string)); for (iter = sign_config.prop_config_map.begin(); iter != sign_config.prop_config_map.end(); iter++) { string cad_prop_name = iter->first; Prop_Config prop_config = iter->second; DOFREE(prop_value); printf("cad_prop_name:%s,prop_location:%s/n", cad_prop_name, prop_config.prop_location); if (prop_config.prop_location._Equal(PROP_LOCATION_ITEM)) { if (item_tag == NULLTAG) { ITKCALL(ifail = ITEM_ask_item_of_rev(rev_tag, &item_tag)); if (ifail != ITK_ok) { goto end; } if (item_tag == NULLTAG) { ITKCALL(ifail = EMH_store_error_s2(EMH_severity_error, ITK_err, ("获取版本对应Item异常"), object_string)); ifail = ITK_err; goto end; } ITKCALL(ifail = AOM_refresh(item_tag, false)); if (ifail != ITK_ok) { goto end; } } ITKCALL(ifail = AOM_UIF_ask_value(item_tag, prop_config.prop_name.c_str(), &prop_value)); } else if (prop_config.prop_location._Equal(PROP_LOCATION_REV)) { ITKCALL(ifail = AOM_UIF_ask_value(rev_tag, prop_config.prop_name.c_str(), &prop_value)); } else if (prop_config.prop_location._Equal(PROP_LOCATION_ITEMMASTER)) { if (item_tag == NULLTAG) { ITKCALL(ifail = ITEM_ask_item_of_rev(rev_tag, &item_tag)); if (ifail != ITK_ok) { goto end; } if (item_tag == NULLTAG) { ITKCALL(ifail = EMH_store_error_s2(EMH_severity_error, ITK_err, ("获取版本对应Item异常"), object_string)); ifail = ITK_err; goto end; } ITKCALL(ifail = AOM_refresh(item_tag, false)); if (ifail != ITK_ok) { goto end; } } if (item_master_tag == NULLTAG) { int master_cnt = 0; tag_t* master_tags = NULL; ITKCALL(ifail = AOM_ask_value_tags(item_tag, "IMAN_master_form", &master_cnt, &master_tags)); if (ifail != ITK_ok) { goto end; } if (master_cnt == 0) { DOFREE(master_tags); ITKCALL(ifail = EMH_store_error_s2(EMH_severity_error, ITK_err, ("获取对象主属性表单异常"), object_string)); ifail = ITK_err; goto end; } item_master_tag = master_tags[0]; DOFREE(master_tags); ITKCALL(ifail = AOM_refresh(item_master_tag, false)); if (ifail != ITK_ok) { goto end; } } ITKCALL(ifail = AOM_UIF_ask_value(item_master_tag, prop_config.prop_name.c_str(), &prop_value)); } else if (prop_config.prop_location._Equal(PROP_LOCATION_REVMASTER)) { if (rev_master_tag == NULLTAG) { int master_cnt = 0; tag_t* master_tags = NULL; ITKCALL(ifail = AOM_ask_value_tags(rev_tag, "IMAN_master_form_rev", &master_cnt, &master_tags)); if (ifail != ITK_ok) { goto end; } if (master_cnt == 0) { DOFREE(master_tags); ITKCALL(ifail = EMH_store_error_s2(EMH_severity_error, ITK_err, ("获取版本主属性表单异常"), object_string)); ifail = ITK_err; goto end; } rev_master_tag = master_tags[0]; DOFREE(master_tags); ITKCALL(ifail = AOM_refresh(rev_master_tag, false)); if (ifail != ITK_ok) { goto end; } } ITKCALL(ifail = AOM_UIF_ask_value(rev_master_tag, prop_config.prop_name.c_str(), &prop_value)); } if (prop_value == NULL || strcmp("", prop_value) == 0) { continue; } info.append("\n").append(cad_prop_name).append("=").append(prop_value); } if (!info.empty()) { info.insert(0, sign_config.title_block_names); } end: DOFREE(object_string); DOFREE(prop_value); return ifail; } int SignCAD(tag_t dataset, const char* dir_path, const char* ref_name, const char* ext, bool remove_file) { int ifail = ITK_ok; char* object_string = NULL; char* origin_file_name = NULL; char temp_file[SS_MAXPATHLEN] = ""; ITKCALL(ifail = AOM_ask_value_string(dataset, "object_string", &object_string)); Log("开始处理数据集:%s", object_string); tag_t spec_dataset_rev = NULLTAG, ref_object = NULLTAG; AE_reference_type_t reference_type; ITKCALL(ifail = AE_ask_dataset_latest_rev(dataset, &spec_dataset_rev)); ITKCALL(ifail = AE_ask_dataset_named_ref2(spec_dataset_rev, ref_name, &reference_type, &ref_object)); if (reference_type == AE_PART_OF) { // 下载数据 ITKCALL(ifail = IMF_ask_original_file_name2(ref_object, &origin_file_name)); strcpy_s(temp_file, dir_path); strcat_s(temp_file, "\\"); strcat_s(temp_file, origin_file_name); ITKCALL(ifail = IMF_export_file(ref_object, temp_file)); if (ifail != ITK_ok) { goto end; } Log("导出到路径:%s", temp_file); // 调用接口 string request; request.append("SYNC|").append(temp_file).append("|"); Log("发送请求:%s", request.c_str()); { SOCKET sock; int valread; const int BUF_SIZE = 1024; char buffer[BUF_SIZE] = { 0 }; struct sockaddr_in serv_addr; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { ITKCALL(ifail = EMH_store_error_s1(EMH_severity_error, ITK_err, ("创建Socket失败"))); ifail = ITK_err; goto end; } serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); serv_addr.sin_port = htons(PORT); // Convert IPv4 and IPv6 addresses from text to binary form if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { Log("连接失败,释放Socket"); closesocket(sock); //关闭套接字 //WSACleanup(); //释放套接字资源 Log("连接已关闭"); ITKCALL(ifail = EMH_store_error_s1(EMH_severity_error, ITK_err, ("无法连接到CAD服务"))); ifail = ITK_err; goto end; } const char* requestU = G2U(request.c_str()); send(sock, requestU, strlen(requestU), 0); Log("请求已发送"); recv(sock, buffer, BUF_SIZE, 0); Log("收到返回信息:%s", buffer); closesocket(sock); //关闭套接字 //WSACleanup(); //释放套接字资源 Log("连接已关闭"); if (strcmp(SOCKET_SUCCESS, buffer) != 0) { ITKCALL(ifail = EMH_store_error_s2(EMH_severity_error, ITK_err, ("签名发生错误"), (buffer))); ifail = ITK_err; goto end; } } // 上传文件 Log("执行完成,开始上传文件"); tag_t new_file_tag = NULLTAG; IMF_file_t file_descriptor; ITKCALL(ifail = IMF_import_file(temp_file, NULL, SS_BINARY, &new_file_tag, &file_descriptor)); ITKCALL(ifail = AOM_lock(new_file_tag)); ITKCALL(ifail = IMF_set_original_file_name2(new_file_tag, origin_file_name)); ITKCALL(ifail = IMF_close_file(file_descriptor)); ITKCALL(ifail = AOM_save(new_file_tag)); ITKCALL(ifail = AOM_unlock(new_file_tag)); ITKCALL(ifail = AOM_lock(spec_dataset_rev)); ITKCALL(ifail = AE_remove_dataset_named_ref_by_tag2(spec_dataset_rev, ref_name, ref_object)); ITKCALL(ifail = AE_add_dataset_named_ref2(spec_dataset_rev, ref_name, AE_PART_OF, new_file_tag)); ITKCALL(ifail = AE_save_myself(spec_dataset_rev)); ITKCALL(ifail = AOM_unlock(spec_dataset_rev)); Log("上传完成"); } end: // 删除文件 if (remove_file && strlen(temp_file) > 0) { remove(temp_file); } DOFREE(origin_file_name); DOFREE(object_string); return ifail; } int Connor_CAD_Signature(EPM_action_message_t msg) { int ifail = ITK_ok, att_cnt = 0, pref_cnt = 0; tag_t root_task = NULLTAG, * attachments = NULL; map sign_config_map; char* object_string = NULL, * object_type = NULL, ** pref_values = NULL; string dataset_rel, dataset_type, dataset_ref; bool has_err = false; logical remove_file = true; tag_t current_task = msg.task; ITKCALL(ifail = EPM_ask_root_task(current_task, &root_task)); if (ifail != ITK_ok) { goto end; } Log("====================================================="); Log("Connor_CAD_Signature 开始执行"); Log("====================================================="); ITKCALL(ifail = EPM_ask_attachments(root_task, EPM_target_attachment, &att_cnt, &attachments)); if (att_cnt == 0) { Log("目标下无引用对象"); goto end; } set_bypass(true); ITKCALL(ifail = PREF_ask_logical_value(PREF_REMOVE_FILE, 0, &remove_file)); if (ifail != ITK_ok) { EMH_clear_last_error(ifail); } if (remove_file) { Log("不保留临时文件"); } else { Log("保留临时文件"); } // 解析上传配置 ITKCALL(ifail = PREF_ask_char_values(PREF_UPLOAD_FILE, &pref_cnt, &pref_values)); if (ifail != ITK_ok) { goto end; } if (pref_cnt < 3) { ITKCALL(ifail = EMH_store_error_s2(EMH_severity_error, ITK_err, ("首选项配置错误"), PREF_SIGNATURE)); ifail = ITK_err; goto end; } dataset_rel.assign(pref_values[0]); dataset_type.assign(pref_values[1]); dataset_ref.assign(pref_values[2]); Log("数据集配置: [%s][%s][%s]", dataset_rel.c_str(), dataset_type.c_str(), dataset_ref.c_str()); DOFREE(pref_values); // 解析签名配置 ifail = ParseConfigFromPreference(sign_config_map); if (ifail != ITK_ok) { goto end; } for (int i = 0; i < att_cnt; i++) { DOFREE(object_string); DOFREE(object_type); tag_t target = attachments[i]; vector dataset_tags; string info, dir_path, info_path; ITKCALL(ifail = AOM_ask_value_string(target, "object_string", &object_string)); ITKCALL(ifail = WSOM_ask_object_type2(target, &object_type)); Log("%d. %s [%s]", i + 1, object_string, object_type); if (sign_config_map.count(object_type) < 1) { continue; } Sign_Config sign_config = sign_config_map[object_type]; // 查询数据集 ifail = GetDatasets(target, dataset_rel, dataset_type, dataset_tags); int dataset_cnt = dataset_tags.size(); Log("找到数据集数量:%d", dataset_cnt); if (dataset_cnt == 0) { continue; } // 获取属性数据 ifail = ReadSignInfo(target, sign_config, info); if (ifail != ITK_ok) { goto end; } if (info.size() < 2) { Log("无签名数据"); continue; } Log("签名数据:\n====================================\n%s\n====================================", info.c_str()); // 创建临时文件夹 ifail = CreateTempFolder(dir_path); if (ifail != ITK_ok) { ifail = ITK_err; ITKCALL(ifail = EMH_store_error_s1(EMH_severity_error, ITK_err, ("创建临时目录失败"))); goto end; } // 准备info.txt info_path.append(dir_path).append("\\info.txt"); printf("映射文件路径:%s,映射属性:%s", info_path.c_str(), info.c_str()); ifail = WriteToFile(info_path.c_str(), G2U(info.c_str())); if (ifail != ITK_ok) { ifail = ITK_err; ITKCALL(ifail = EMH_store_error_s1(EMH_severity_error, ITK_err, ("创建属性映射文件失败"))); goto end; } for (int j = 0; j < dataset_cnt; j++) { tag_t dataset_tag = dataset_tags[j]; ifail = SignCAD(dataset_tag, dir_path.c_str(), dataset_ref.c_str(), "dwg", remove_file); if (ifail != ITK_ok) { has_err = true; } } // 清理文件 if (remove_file) { remove(info_path.c_str()); std::experimental::filesystem::remove_all(dir_path.c_str()); } //rmdir(dir_path.c_str()); } end: Log("====================================================="); Log("Connor_CAD_Signature 执行结束"); Log("====================================================="); set_bypass(false); if (has_err) { ifail = ITK_err; } DOFREE(pref_values); DOFREE(object_string); DOFREE(object_type); DOFREE(attachments); return ifail; } int Test(tag_t dataset, const char* dir_path, const char* ref_name, const char* ext) { int ifail = ITK_ok; char* object_string = NULL; char* origin_file_name = NULL; char temp_file[SS_MAXPATHLEN] = ""; string pdf_path; ITKCALL(ifail = AOM_ask_value_string(dataset, "object_string", &object_string)); Log("开始处理数据集:%s", object_string); tag_t spec_dataset_rev = NULLTAG, ref_object = NULLTAG; AE_reference_type_t reference_type; ITKCALL(ifail = AE_ask_dataset_latest_rev(dataset, &spec_dataset_rev)); ITKCALL(ifail = AE_ask_dataset_named_ref2(spec_dataset_rev, ref_name, &reference_type, &ref_object)); if (reference_type == AE_PART_OF) { // 下载数据 ITKCALL(ifail = IMF_ask_original_file_name2(ref_object, &origin_file_name)); strcpy_s(temp_file, dir_path); strcat_s(temp_file, "\\"); strcat_s(temp_file, origin_file_name); ITKCALL(ifail = IMF_export_file(ref_object, temp_file)); if (ifail != ITK_ok) { goto end; } Log("导出到路径:%s", temp_file); // 调用接口 { string request; request.append("SYNC|").append(temp_file).append("|"); Log("发送请求:%s", request.c_str()); SOCKET sock; int valread; const int BUF_SIZE = 1024; char buffer[BUF_SIZE] = { 0 }; struct sockaddr_in serv_addr; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { ITKCALL(ifail = EMH_store_error_s1(EMH_severity_error, ITK_err, ("创建Socket失败"))); ifail = ITK_err; goto end; } serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); serv_addr.sin_port = htons(PORT); // Convert IPv4 and IPv6 addresses from text to binary form if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { Log("连接失败,释放Socket"); closesocket(sock); //关闭套接字 //WSACleanup(); //释放套接字资源 Log("连接已关闭"); ITKCALL(ifail = EMH_store_error_s1(EMH_severity_error, ITK_err, ("无法连接到CAD服务"))); ifail = -1; goto end; } const char* requestU = (request.c_str()); send(sock, requestU, strlen(requestU), 0); Log("请求已发送"); recv(sock, buffer, BUF_SIZE, 0); Log("收到返回信息:%s", buffer); closesocket(sock); //关闭套接字 //WSACleanup(); //释放套接字资源 Log("连接已关闭"); if (strcmp(SOCKET_SUCCESS, buffer) != 0) { ITKCALL(ifail = EMH_store_error_s2(EMH_severity_error, ITK_err, ("签名发生错误"), (buffer))); ifail = ITK_err; goto end; } } pdf_path.assign(temp_file); pdf_path = pdf_path.substr(0, pdf_path.length() - 4).append(".pdf"); // 调用接口 { string request; request.append("PDF|").append(temp_file).append("|"); Log("发送请求:%s", request.c_str()); int sock; int valread; const int BUF_SIZE = 1024; char buffer[BUF_SIZE] = { 0 }; struct sockaddr_in serv_addr; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { ITKCALL(ifail = EMH_store_error_s1(EMH_severity_error, ITK_err, ("创建Socket失败"))); ifail = ITK_err; goto end; } serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); serv_addr.sin_port = htons(PORT); // Convert IPv4 and IPv6 addresses from text to binary form if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { Log("连接失败,释放Socket"); closesocket(sock); //关闭套接字 //WSACleanup(); //释放套接字资源 Log("连接已关闭"); ITKCALL(ifail = EMH_store_error_s1(EMH_severity_error, ITK_err, ("无法连接到CAD服务"))); ifail = ITK_err; goto end; } const char* requestU = request.c_str(); send(sock, requestU, strlen(requestU), 0); Log("请求已发送"); recv(sock, buffer, BUF_SIZE, 0); Log("收到返回信息:%s", buffer); closesocket(sock); //关闭套接字 //WSACleanup(); //释放套接字资源 Log("连接已关闭"); if (strcmp(SOCKET_SUCCESS, buffer) != 0) { ITKCALL(ifail = EMH_store_error_s2(EMH_severity_error, ITK_err, ("转PDF发生错误"), (buffer))); ifail = ITK_err; goto end; } } } end: // 删除文件 /*if (strlen(temp_file) > 0) { remove(temp_file); } if (pdf_path.size() > 0) { remove(pdf_path.c_str()); }*/ DOFREE(origin_file_name); DOFREE(object_string); return ifail; } int Connor_CAD_Test(EPM_action_message_t msg) { int ifail = ITK_ok, att_cnt = 0, pref_cnt = 0; tag_t root_task = NULLTAG, * attachments = NULL; map sign_config_map; char* object_string = NULL, * object_type = NULL, ** pref_values = NULL; string dataset_rel, dataset_type, dataset_ref; bool has_err = false; int counter = 1; tag_t current_task = msg.task; ITKCALL(ifail = EPM_ask_root_task(current_task, &root_task)); if (ifail != ITK_ok) { goto end; } Log("====================================================="); Log("Connor_CAD_Test 开始执行"); Log("====================================================="); ITKCALL(ifail = EPM_ask_attachments(root_task, EPM_target_attachment, &att_cnt, &attachments)); if (att_cnt == 0) { Log("目标下无引用对象"); goto end; } // 解析上传配置 ITKCALL(ifail = PREF_ask_char_values(PREF_UPLOAD_FILE, &pref_cnt, &pref_values)); if (ifail != ITK_ok) { goto end; } if (pref_cnt < 3) { ITKCALL(ifail = EMH_store_error_s2(EMH_severity_error, ITK_err, ("首选项配置错误"), PREF_SIGNATURE)); ifail = ITK_err; goto end; } dataset_rel.assign(pref_values[0]); dataset_type.assign(pref_values[1]); dataset_ref.assign(pref_values[2]); Log("数据集配置: [%s][%s][%s]", dataset_rel.c_str(), dataset_type.c_str(), dataset_ref.c_str()); DOFREE(pref_values); // 解析签名配置 ifail = ParseConfigFromPreference(sign_config_map); if (ifail != ITK_ok) { goto end; } while (true) { Log("第%d次循环测试", counter++); for (int i = 0; i < att_cnt; i++) { DOFREE(object_string); DOFREE(object_type); tag_t target = attachments[i]; vector dataset_tags; string info, dir_path, info_path; ITKCALL(ifail = AOM_ask_value_string(target, "object_string", &object_string)); ITKCALL(ifail = WSOM_ask_object_type2(target, &object_type)); Log("%d. %s [%s]", i + 1, object_string, object_type); if (sign_config_map.count(object_type) < 1) { continue; } Sign_Config sign_config = sign_config_map[object_type]; // 查询数据集 ifail = GetDatasets(target, dataset_rel, dataset_type, dataset_tags); int dataset_cnt = dataset_tags.size(); Log("找到数据集数量:%d", dataset_cnt); if (dataset_cnt == 0) { continue; } // 获取属性数据 ifail = ReadSignInfo(target, sign_config, info); if (ifail != ITK_ok) { goto end; } if (info.size() < 2) { Log("无签名数据"); continue; } Log("签名数据:\n====================================\n%s\n====================================", info.c_str()); // 创建临时文件夹 ifail = CreateTempFolder(dir_path); if (ifail != ITK_ok) { ifail = ITK_err; ITKCALL(ifail = EMH_store_error_s1(EMH_severity_error, ITK_err, ("创建临时目录失败"))); goto end; } // 准备info.txt info_path.append(dir_path).append("\\info.txt"); ifail = WriteToFile(info_path.c_str(), info.c_str()); if (ifail != ITK_ok) { ifail = ITK_err; ITKCALL(ifail = EMH_store_error_s1(EMH_severity_error, ITK_err, ("创建属性映射文件失败"))); goto end; } for (int j = 0; j < dataset_cnt; j++) { tag_t dataset_tag = dataset_tags[j]; ifail = Test(dataset_tag, dir_path.c_str(), dataset_ref.c_str(), "dwg"); if (ifail != ITK_ok) { has_err = true; } if (ifail == -1) { ifail = ITK_err; goto end; } } // 清理文件 /*remove(info_path.c_str()); rmdir(dir_path.c_str());*/ } } end: Log("====================================================="); Log("Connor_CAD_Test 执行结束"); Log("====================================================="); if (has_err) { ifail = ITK_err; } DOFREE(pref_values); DOFREE(object_string); DOFREE(object_type); DOFREE(attachments); return ifail; }