static void sttSendPrivateMessage( JABBER_LIST_ITEM* item, const TCHAR* nick ) { TCHAR szFullJid[ 256 ]; mir_sntprintf( szFullJid, SIZEOF(szFullJid), _T("%s/%s"), item->jid, nick ); HANDLE hContact = JabberDBCreateContact( szFullJid, NULL, TRUE, FALSE ); if ( hContact != NULL ) { for ( int i=0; i < item->resourceCount; i++ ) { if ( _tcsicmp( item->resource[i].resourceName, nick ) == 0 ) { JSetWord( hContact, "Status", item->resource[i].status ); break; } } DBWriteContactSettingByte( hContact, "CList", "Hidden", 1 ); JSetStringT( hContact, "Nick", nick ); DBWriteContactSettingDword( hContact, "Ignore", "Mask1", 0 ); JCallService( MS_MSG_SENDMESSAGE, ( WPARAM )hContact, 0 ); } }
void JabberDBAddAuthRequest( TCHAR* jid, TCHAR* nick ) { HANDLE hContact = JabberDBCreateContact( jid, NULL, FALSE, TRUE ); JDeleteSetting( hContact, "Hidden" ); //JSetStringT( hContact, "Nick", nick ); #if defined( _UNICODE ) char* szJid = u2a( jid ); char* szNick = u2a( nick ); #else char* szJid = jid; char* szNick = nick; #endif //blob is: uin( DWORD ), hContact( HANDLE ), nick( ASCIIZ ), first( ASCIIZ ), last( ASCIIZ ), email( ASCIIZ ), reason( ASCIIZ ) //blob is: 0( DWORD ), hContact( HANDLE ), nick( ASCIIZ ), ""( ASCIIZ ), ""( ASCIIZ ), email( ASCIIZ ), ""( ASCIIZ ) DBEVENTINFO dbei = {0}; dbei.cbSize = sizeof( DBEVENTINFO ); dbei.szModule = jabberProtoName; dbei.timestamp = ( DWORD )time( NULL ); dbei.flags = 0; dbei.eventType = EVENTTYPE_AUTHREQUEST; dbei.cbBlob = sizeof( DWORD )+ sizeof( HANDLE ) + strlen( szNick ) + strlen( szJid ) + 5; PBYTE pCurBlob = dbei.pBlob = ( PBYTE ) mir_alloc( dbei.cbBlob ); *(( PDWORD ) pCurBlob ) = 0; pCurBlob += sizeof( DWORD ); *(( PHANDLE ) pCurBlob ) = hContact; pCurBlob += sizeof( HANDLE ); strcpy(( char* )pCurBlob, szNick ); pCurBlob += strlen( szNick )+1; *pCurBlob = '\0'; pCurBlob++; //firstName *pCurBlob = '\0'; pCurBlob++; //lastName strcpy(( char* )pCurBlob, szJid ); pCurBlob += strlen( szJid )+1; *pCurBlob = '\0'; //reason JCallService( MS_DB_EVENT_ADD, ( WPARAM ) ( HANDLE ) NULL, ( LPARAM )&dbei ); JabberLog( "Setup DBAUTHREQUEST with nick='" TCHAR_STR_PARAM "' jid='" TCHAR_STR_PARAM "'", szNick, szJid ); #if defined( _UNICODE ) mir_free( szJid ); mir_free( szNick ); #endif }
void JabberIqResultGetRoster(XmlNode *iqNode, void *userdata) { //struct ThreadData *info = (struct ThreadData *) userdata; XmlNode *queryNode; char *type; char *str; // RECVED: roster information // ACTION: populate LIST_ROSTER and create contact for any new rosters JabberLog("<iq/> iqIdGetRoster"); if ((type=JabberXmlGetAttrValue(iqNode, "type")) == NULL) return; if ((queryNode=JabberXmlGetChild(iqNode, "query")) == NULL) return; if (!strcmp(type, "result")) { str = JabberXmlGetAttrValue(queryNode, "xmlns"); if (str!=NULL && !strcmp(str, "jabber:iq:roster")) { DBVARIANT dbv; XmlNode *itemNode, *groupNode; JABBER_SUBSCRIPTION sub; JABBER_LIST_ITEM *item; HANDLE hContact; char *jid, *name, *nick; int i, oldStatus; for (i=0; i<queryNode->numChild; i++) { itemNode = queryNode->child[i]; if (!strcmp(itemNode->name, "item")) { str = JabberXmlGetAttrValue(itemNode, "subscription"); if (str==NULL) sub = SUB_NONE; else if (!strcmp(str, "both")) sub = SUB_BOTH; else if (!strcmp(str, "to")) sub = SUB_TO; else if (!strcmp(str, "from")) sub = SUB_FROM; else sub = SUB_NONE; //if (str!=NULL && (!strcmp(str, "to") || !strcmp(str, "both"))) { if ((jid=JabberXmlGetAttrValue(itemNode, "jid")) != NULL) { if ((name=JabberXmlGetAttrValue(itemNode, "name")) != NULL) { nick = JabberTextDecode(name); } else { nick = JabberLocalNickFromJID(jid); } if (nick != NULL) { item = JabberListAdd(LIST_ROSTER, jid); if (item->nick) free(item->nick); item->nick = nick; item->subscription = sub; if ((hContact=JabberHContactFromJID(jid)) == NULL) { // Received roster has a new JID. // Add the jid (with empty resource) to Miranda contact list. hContact = JabberDBCreateContact(jid, nick, FALSE, TRUE); } DBWriteContactSettingString(hContact, "CList", "MyHandle", nick); if (item->group) free(item->group); if ((groupNode=JabberXmlGetChild(itemNode, "group"))!=NULL && groupNode->text!=NULL) { item->group = JabberTextDecode(groupNode->text); JabberContactListCreateGroup(item->group); // Don't set group again if already correct, or Miranda may show wrong group count in some case if (!DBGetContactSetting(hContact, "CList", "Group", &dbv)) { if (strcmp(dbv.pszVal, item->group)) DBWriteContactSettingString(hContact, "CList", "Group", item->group); DBFreeVariant(&dbv); } else DBWriteContactSettingString(hContact, "CList", "Group", item->group); } else { item->group = NULL; DBDeleteContactSetting(hContact, "CList", "Group"); } } } } } // Delete orphaned contacts (if roster sync is enabled) if (DBGetContactSettingByte(NULL, jabberProtoName, "RosterSync", FALSE) == TRUE) { HANDLE *list; int listSize, listAllocSize; listSize = listAllocSize = 0; list = NULL; hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); while (hContact != NULL) { str = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); if(str!=NULL && !strcmp(str, jabberProtoName)) { if (!DBGetContactSetting(hContact, jabberProtoName, "jid", &dbv)) { if (!JabberListExist(LIST_ROSTER, dbv.pszVal)) { JabberLog("Syncing roster: preparing to delete %s (hContact=0x%x)", dbv.pszVal, hContact); if (listSize >= listAllocSize) { listAllocSize = listSize + 100; if ((list=(HANDLE *) realloc(list, listAllocSize)) == NULL) { listSize = 0; break; } } list[listSize++] = hContact; } DBFreeVariant(&dbv); } } hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0); } for (i=0; i<listSize; i++) { JabberLog("Syncing roster: deleting 0x%x", list[i]); CallService(MS_DB_CONTACT_DELETE, (WPARAM) list[i], 0); } if (list != NULL) free(list); } /////////////////////////////////////// { CLISTMENUITEM clmi; memset(&clmi, 0, sizeof(CLISTMENUITEM)); clmi.cbSize = sizeof(CLISTMENUITEM); clmi.flags = CMIM_FLAGS; CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) hMenuMUC, (LPARAM) &clmi); CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) hMenuChats, (LPARAM) &clmi); } jabberOnline = TRUE; JabberLog("Status changed via THREADSTART"); oldStatus = jabberStatus; switch (jabberDesiredStatus) { case ID_STATUS_ONLINE: case ID_STATUS_NA: case ID_STATUS_FREECHAT: case ID_STATUS_INVISIBLE: jabberStatus = jabberDesiredStatus; break; case ID_STATUS_AWAY: case ID_STATUS_ONTHEPHONE: case ID_STATUS_OUTTOLUNCH: jabberStatus = ID_STATUS_AWAY; break; case ID_STATUS_DND: case ID_STATUS_OCCUPIED: jabberStatus = ID_STATUS_DND; break; } JabberSendPresence(jabberStatus); ProtoBroadcastAck(jabberProtoName, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldStatus, jabberStatus); ////////////////////////////////// } } }
void TlenProcessPresence(XmlNode *node, TlenProtocol *proto) { HANDLE hContact; XmlNode *showNode, *statusNode; JABBER_LIST_ITEM *item; char *from, *type, *nick, *show; int status, laststatus = ID_STATUS_OFFLINE; char *p; if ((from=JabberXmlGetAttrValue(node, "from")) != NULL) { if (JabberListExist(proto, LIST_CHATROOM, from)); //JabberGroupchatProcessPresence(node, userdata); else { type = JabberXmlGetAttrValue(node, "type"); item = JabberListGetItemPtr(proto, LIST_ROSTER, from); if (item != NULL) { if (proto->tlenOptions.enableAvatars) { TlenProcessPresenceAvatar(proto, node, item); } } if (type==NULL || (!strcmp(type, "available"))) { if ((nick=JabberLocalNickFromJID(from)) != NULL) { if ((hContact=JabberHContactFromJID(proto, from)) == NULL) hContact = JabberDBCreateContact(proto, from, nick, FALSE); if (!JabberListExist(proto, LIST_ROSTER, from)) { JabberLog(proto, "Receive presence online from %s (who is not in my roster)", from); JabberListAdd(proto, LIST_ROSTER, from); } status = ID_STATUS_ONLINE; if ((showNode=JabberXmlGetChild(node, "show")) != NULL) { if ((show=showNode->text) != NULL) { if (!strcmp(show, "away")) status = ID_STATUS_AWAY; else if (!strcmp(show, "xa")) status = ID_STATUS_NA; else if (!strcmp(show, "dnd")) status = ID_STATUS_DND; else if (!strcmp(show, "chat")) status = ID_STATUS_FREECHAT; else if (!strcmp(show, "unavailable")) { // Always show invisible (on old Tlen client) as invisible (not offline) status = ID_STATUS_OFFLINE; } } } statusNode = JabberXmlGetChild(node, "status"); if (statusNode) p = JabberTextDecode(statusNode->text); else p = NULL; JabberListAddResource(proto, LIST_ROSTER, from, status, statusNode?p:NULL); if (p) { DBWriteContactSettingString(hContact, "CList", "StatusMsg", p); mir_free(p); } else { DBDeleteContactSetting(hContact, "CList", "StatusMsg"); } // Determine status to show for the contact and request version information if (item != NULL) { laststatus = item->status; item->status = status; } if (strchr(from, '@')!=NULL || DBGetContactSettingByte(NULL, proto->iface.m_szModuleName, "ShowTransport", TRUE)==TRUE) { if (DBGetContactSettingWord(hContact, proto->iface.m_szModuleName, "Status", ID_STATUS_OFFLINE) != status) DBWriteContactSettingWord(hContact, proto->iface.m_szModuleName, "Status", (WORD) status); } if (item != NULL) { if (!item->infoRequested) { int iqId = JabberSerialNext(proto); item->infoRequested = TRUE; JabberSend( proto, "<iq type='get' id='"JABBER_IQID"%d'><query xmlns='jabber:iq:info' to='%s'></query></iq>", iqId, from); } if (proto->tlenOptions.enableVersion && !item->versionRequested) { item->versionRequested = TRUE; if (proto->iface.m_iStatus != ID_STATUS_INVISIBLE) { JabberSend( proto, "<message to='%s' type='iq'><iq type='get'><query xmlns='jabber:iq:version'/></iq></message>", from ); } } } JabberLog(proto, "%s (%s) online, set contact status to %d", nick, from, status); mir_free(nick); } } else if (!strcmp(type, "unavailable")) { if (!JabberListExist(proto, LIST_ROSTER, from)) { JabberLog(proto, "Receive presence offline from %s (who is not in my roster)", from); JabberListAdd(proto, LIST_ROSTER, from); } else { JabberListRemoveResource(proto, LIST_ROSTER, from); } status = ID_STATUS_OFFLINE; statusNode = JabberXmlGetChild(node, "status"); if (statusNode) { if (proto->tlenOptions.offlineAsInvisible) { status = ID_STATUS_INVISIBLE; } p = JabberTextDecode(statusNode->text); JabberListAddResource(proto, LIST_ROSTER, from, status, p); if ((hContact=JabberHContactFromJID(proto, from)) != NULL) { if (p) { DBWriteContactSettingString(hContact, "CList", "StatusMsg", p); } else { DBDeleteContactSetting(hContact, "CList", "StatusMsg"); } } if (p) mir_free(p); } if ((item=JabberListGetItemPtr(proto, LIST_ROSTER, from)) != NULL) { // Determine status to show for the contact based on the remaining resources item->status = status; item->versionRequested = FALSE; item->infoRequested = FALSE; } if ((hContact=JabberHContactFromJID(proto, from)) != NULL) { if (strchr(from, '@')!=NULL || DBGetContactSettingByte(NULL, proto->iface.m_szModuleName, "ShowTransport", TRUE)==TRUE) { if (DBGetContactSettingWord(hContact, proto->iface.m_szModuleName, "Status", ID_STATUS_OFFLINE) != status) DBWriteContactSettingWord(hContact, proto->iface.m_szModuleName, "Status", (WORD) status); } if (item != NULL && item->isTyping) { item->isTyping = FALSE; CallService(MS_PROTO_CONTACTISTYPING, (WPARAM) hContact, PROTOTYPE_CONTACTTYPING_OFF); } JabberLog(proto, "%s offline, set contact status to %d", from, status); } } else if (!strcmp(type, "subscribe")) { if (strchr(from, '@') == NULL) { // automatically send authorization allowed to agent/transport JabberSend(proto, "<presence to='%s' type='subscribed'/>", from); } else if ((nick=JabberNickFromJID(from)) != NULL) { JabberLog(proto, "%s (%s) requests authorization", nick, from); JabberDBAddAuthRequest(proto, from, nick); mir_free(nick); } } else if (!strcmp(type, "subscribed")) { if ((item=JabberListGetItemPtr(proto, LIST_ROSTER, from)) != NULL) { if (item->subscription == SUB_FROM) item->subscription = SUB_BOTH; else if (item->subscription == SUB_NONE) { item->subscription = SUB_TO; } } } } } }
static int TlenMUCHandleEvent(WPARAM wParam, LPARAM lParam) { HANDLE hContact; int id; MUCCEVENT *mucce=(MUCCEVENT *) lParam; if (!strcmp(mucce->pszModule, jabberProtoName)) { JabberLog("ME ! %d", mucce->iType); switch (mucce->iType) { case MUCC_EVENT_INVITE: TlenMUCSendInvitation(mucce->pszID, mucce->pszNick); break; case MUCC_EVENT_MESSAGE: TlenMUCSendMessage(mucce); break; case MUCC_EVENT_TOPIC: TlenMUCSendTopic(mucce); break; case MUCC_EVENT_LEAVE: TlenMUCSendPresence(mucce->pszID, NULL, ID_STATUS_OFFLINE); break; case MUCC_EVENT_QUERY_GROUPS: TlenMUCSendQuery(1, mucce->pszID, 0); break; case MUCC_EVENT_QUERY_ROOMS: TlenMUCSendQuery(2, mucce->pszID, mucce->dwData); break; case MUCC_EVENT_QUERY_SEARCH: TlenMUCSendQuery(3, mucce->pszName, 0); break; case MUCC_EVENT_QUERY_USERS: JabberLog("query3=%d",mucce->dwFlags); switch (mucce->dwFlags) { case MUCC_EF_USER_OWNER: id = 1; break; case MUCC_EF_USER_ADMIN: id = 2; break; case MUCC_EF_USER_MEMBER: id = 3; break; case MUCC_EF_USER_BANNED: id = 4; break; case MUCC_EF_USER_MODERATOR: id = 6; break; default: id = 0; } TlenMUCSendQuery(4, mucce->pszID, id); break; case MUCC_EVENT_REGISTER_NICK: TlenMUCSendQuery(6, mucce->pszNick, 0); break; case MUCC_EVENT_REMOVE_NICK: TlenMUCSendQuery(6, mucce->pszNick, 1); break; case MUCC_EVENT_REGISTER_ROOM: id = JabberSerialNext(); if (jabberOnline) { if (mucce->pszNick!=NULL) { JabberSend(jabberThreadInfo->s, "<p to='c' tp='c' id='"JABBER_IQID"%d' x='%d' n='%s' p='%s' nick='%s'/>", id, mucce->dwFlags | 0x10, mucce->pszName, mucce->pszID); } else { JabberSend(jabberThreadInfo->s, "<p to='c' tp='c' id='"JABBER_IQID"%d' x='%d' n='%s' p='%s'/>", id, mucce->dwFlags | 0x10, mucce->pszName, mucce->pszID); } } break; case MUCC_EVENT_REMOVE_ROOM: if (jabberOnline) { JabberSend(jabberThreadInfo->s, "<p to='%s' type='d'/>", mucce->pszID); JabberListRemove(LIST_CHATROOM, mucce->pszID); // TlenMUCSendPresence(mucce->pszID, NULL, ID_STATUS_OFFLINE); } break; case MUCC_EVENT_KICK_BAN: if (jabberOnline) { char *nick; nick = JabberResourceFromJID(mucce->pszUID); if (!isSelf(mucce->pszID, nick)) { char *reason = JabberTextEncode(mucce->pszText); JabberSend(jabberThreadInfo->s, "<p to='%s'><x><i i='%s' a='4' ex='%d' rs='%s'/></x></p>", mucce->pszID, nick, mucce->dwData, reason); mir_free(reason); } mir_free(nick); } break; case MUCC_EVENT_UNBAN: if (jabberOnline) { char *nick; nick = JabberResourceFromJID(mucce->pszUID); if (!isSelf(mucce->pszID, nick)) { JabberSend(jabberThreadInfo->s, "<p to='%s'><x><i i='%s' a='0'/></x></p>", mucce->pszID, nick); } mir_free(nick); } break; case MUCC_EVENT_SET_USER_ROLE: if (jabberOnline) { char *nick; nick = JabberResourceFromJID(mucce->pszUID); if (!isSelf(mucce->pszID, nick)) { if (mucce->dwFlags == MUCC_EF_USER_ADMIN) { id = 2; } else if (mucce->dwFlags == MUCC_EF_USER_MEMBER) { id = 3; } else { id = 0; } JabberSend(jabberThreadInfo->s, "<p to='%s'><x><i i='%s' a='%d' /></x></p>", mucce->pszID, nick, id); } mir_free(nick); } break; case MUCC_EVENT_QUERY_USER_NICKS: TlenMUCSendQuery(7, mucce->pszID, 0); break; case MUCC_EVENT_QUERY_USER_ROOMS: TlenMUCSendQuery(8, mucce->pszID, 0); break; case MUCC_EVENT_QUERY_CONTACTS: TlenMUCQueryContacts(mucce->pszID); break; case MUCC_EVENT_JOIN: if (jabberOnline) { if (mucce->pszID==NULL || strlen(mucce->pszID)==0) { if (mucce->pszName==NULL || strlen(mucce->pszName)==0) { // create a new chat room id = JabberSerialNext(); JabberSend(jabberThreadInfo->s, "<p to='c' tp='c' id='"JABBER_IQID"%d'/>", id); } else { // find a chat room by name TlenMUCSendQuery(3, mucce->pszName, 0); } } else { // join existing chat room if (!TlenMUCCreateWindow(mucce->pszID, mucce->pszName, mucce->dwFlags, mucce->pszNick, NULL)) { TlenMUCSendPresence(mucce->pszID, mucce->pszNick, ID_STATUS_ONLINE); } } } break; case MUCC_EVENT_START_PRIV: if (jabberOnline) { JABBER_LIST_ITEM *item; item = JabberListGetItemPtr(LIST_CHATROOM, mucce->pszID); if (item!=NULL) { char *nick; nick = JabberResourceFromJID(mucce->pszUID); if (!isSelf(mucce->pszID, nick)) { if (nick[0]=='~' || item->nick!=NULL) { char str[256]; sprintf(str, "%s/%s", mucce->pszID, nick); hContact = JabberDBCreateContact(str, nick, TRUE); //(char *)mucce->pszUID DBWriteContactSettingByte(hContact, jabberProtoName, "bChat", TRUE); CallService(MS_MSG_SENDMESSAGE, (WPARAM) hContact, (LPARAM) NULL); } else { DBVARIANT dbv; if (!DBGetContactSetting(NULL, jabberProtoName, "LoginServer", &dbv)) { char str[512]; _snprintf(str, sizeof(str), "%s@%s", nick, dbv.pszVal); DBFreeVariant(&dbv); hContact = JabberDBCreateContact(str, nick, TRUE); CallService(MS_MSG_SENDMESSAGE, (WPARAM) hContact, (LPARAM) NULL); } } } mir_free(nick); } } break; } } return 0; }
static int ServiceParseXmppURI(WPARAM wParam, LPARAM lParam) { char *arg = (char*)lParam; char *jid; UNREFERENCED_PARAMETER(wParam); if (arg == NULL) return 1; /* sanity check */ /* skip leading prefix */ arg = strchr(arg, ':'); if (arg == NULL) return 1; /* parse failed */ for (++arg; *arg == '/'; ++arg); /* complete specification: http://www.xmpp.org/extensions/xep-0147.html send message: xmpp:JID?message;subject=TEXT&body=TEXT add user: xmpp:JID?roster remove user: xmpp:JID?remove */ /* user id */ arg = strchr(jid = arg, '?'); if (arg == NULL) arg += mir_strlen(arg); /* points to terminating nul */ else *(arg++) = 0; if (*jid == 0) return 1; /* parse failed */ /* send a message to a contact */ else if (*arg == 0 || (!_strnicmp(arg, "message", 7) && (*(arg + 7) == ';' || *(arg + 7) == 0))) { char *tok, *subj = NULL, *body = NULL; MCONTACT hContact; char msg[1024]; arg += 7; while (*arg == ';') ++arg; tok = strtok(arg, "&"); /* first token */ while (tok != NULL) { if (!_strnicmp(tok, "subject=", 8) && *(tok + 8) != 0) subj = Netlib_UrlDecode(tok + 8); if (!_strnicmp(tok, "body=", 5) && *(tok + 5) != 0) body = Netlib_UrlDecode(tok + 5); tok = strtok(NULL, "&"); /* next token */ } if (ServiceExists(MS_MSG_SENDMESSAGE)) { hContact = JabberDBCreateContact(jid, jid, TRUE, FALSE); if (subj != NULL && body != NULL) { mir_snprintf(msg, _countof(msg), "%.128s %s", subj, body); body = msg; } else if (body == NULL) body = subj; if (hContact != NULL) CallService(MS_MSG_SENDMESSAGE, hContact, (LPARAM)body); } return 0; } /* add user to contact list */ else if (!_strnicmp(arg, "roster", 6) && (*(arg + 6) == ';' || *(arg + 6) == 0)) { ADDCONTACTSTRUCT acs; PROTOSEARCHRESULT psr; if (JabberHContactFromJID(jid) == NULL) { /* does not yet check if jid belongs to current user */ acs.handleType = HANDLE_SEARCHRESULT; acs.szProto = jabberProtoName; acs.psr = &psr; memset(&psr, 0, sizeof(PROTOSEARCHRESULT)); psr.cbSize = sizeof(PROTOSEARCHRESULT); psr.nick.t = jid; CallService(MS_ADDCONTACT_SHOW, 0, (LPARAM)&acs); } return 0; } /* remove user from contact list */ else if (!_strnicmp(arg, "remove", 6) && (*(arg + 6) == ';' || *(arg + 6) == 0)) { MCONTACT hContact; hContact = JabberHContactFromJID(jid); if (hContact == NULL) /* not yet implemented: show standard miranda dialog here */ CallService(MS_DB_CONTACT_DELETE, hContact, 0); return 0; } /* add user subscription */ else if (!_strnicmp(arg, "subscribe", 9) && (*(arg + 9) == ';' || *(arg + 9) == 0)) { /* not yet implemented */ return 0; } /* remove user subscription */ else if (!_strnicmp(arg, "unsubscribe", 11) && (*(arg + 11) == ';' || *(arg + 11) == 0)) { /* not yet implemented */ return 0; } return 1; /* parse failed */ }