Commit 869aaa5
Changed files (1)
pkg
signal
pkg/signal/server.go
@@ -419,51 +419,45 @@ func (s *Server) handleSearchMessages(req mcp.CallToolRequest) (mcp.CallToolResu
}
}
- if err := s.ensureConnection(); err != nil {
- return mcp.NewToolError(fmt.Sprintf("Database connection failed: %v", err)), nil
- }
-
- query := `
- SELECT m.id, m.conversationId, m.type, m.body, m.sourceServiceId, m.sent_at,
+ query := `SELECT m.id, m.conversationId, m.type, m.body, m.sourceServiceId, m.sent_at,
COALESCE(c.name, c.profileName, c.e164, c.id) as conversation_name
FROM messages m
JOIN conversations c ON m.conversationId = c.id
- WHERE m.body LIKE ?
+ WHERE m.body LIKE '%` + searchTerm + `%'
AND m.type NOT IN ('keychange', 'profile-change')
AND m.type IS NOT NULL
ORDER BY m.sent_at DESC
- LIMIT ?
- `
+ LIMIT ` + strconv.Itoa(limit)
- rows, err := s.db.Query(query, "%"+searchTerm+"%", limit)
+ output, err := s.executeQuery(query)
if err != nil {
return mcp.NewToolError(fmt.Sprintf("Search failed: %v", err)), nil
}
- defer rows.Close()
-
- var messages []Message
- for rows.Next() {
- var m Message
- var sentAtMs int64
- var sourceServiceId string
- var conversationName string
-
- err := rows.Scan(&m.ID, &m.ConversationID, &m.Type, &m.Body, &sourceServiceId, &sentAtMs, &conversationName)
- if err != nil {
- continue
- }
- m.SentAt = time.Unix(sentAtMs/1000, (sentAtMs%1000)*1000000)
- m.From = "Unknown"
- m.To = conversationName
-
- messages = append(messages, m)
+ var messages []map[string]interface{}
+ if err := json.Unmarshal(output, &messages); err != nil {
+ return mcp.NewToolError(fmt.Sprintf("Failed to parse search results: %v", err)), nil
}
result := fmt.Sprintf("Found %d messages containing '%s':\n\n", len(messages), searchTerm)
for _, msg := range messages {
- result += fmt.Sprintf("**%s** (%s)\n%s\n---\n",
- msg.To, msg.SentAt.Format("2006-01-02 15:04"), msg.Body)
+ conversationName := msg["conversation_name"]
+ if conversationName == nil {
+ conversationName = "Unknown"
+ }
+
+ body := msg["body"]
+ if body == nil {
+ body = ""
+ }
+
+ if sentAt, ok := msg["sent_at"].(float64); ok {
+ t := time.Unix(int64(sentAt/1000), (int64(sentAt)%1000)*1000000)
+ result += fmt.Sprintf("**%s** (%s)\n%s\n---\n",
+ conversationName, t.Format("2006-01-02 15:04"), body)
+ } else {
+ result += fmt.Sprintf("**%s**\n%s\n---\n", conversationName, body)
+ }
}
return mcp.NewToolResult(mcp.NewTextContent(result)), nil
@@ -484,82 +478,50 @@ func (s *Server) handleGetConversation(req mcp.CallToolRequest) (mcp.CallToolRes
}
}
- if err := s.ensureConnection(); err != nil {
- return mcp.NewToolError(fmt.Sprintf("Database connection failed: %v", err)), nil
- }
-
- query := `
- SELECT m.id, m.type, m.body, m.sourceServiceId, m.sent_at, m.json
+ query := `SELECT m.id, m.type, m.body, m.sourceServiceId, m.sent_at, m.json
FROM messages m
- WHERE m.conversationId = ?
+ WHERE m.conversationId = '` + conversationID + `'
AND m.type NOT IN ('keychange', 'profile-change')
AND m.type IS NOT NULL
ORDER BY m.sent_at DESC
- LIMIT ?
- `
+ LIMIT ` + strconv.Itoa(limit)
- rows, err := s.db.Query(query, conversationID, limit)
+ output, err := s.executeQuery(query)
if err != nil {
return mcp.NewToolError(fmt.Sprintf("Query failed: %v", err)), nil
}
- defer rows.Close()
-
- var messages []Message
- for rows.Next() {
- var m Message
- var sentAtMs int64
- var sourceServiceId string
- var jsonData sql.NullString
-
- err := rows.Scan(&m.ID, &m.Type, &m.Body, &sourceServiceId, &sentAtMs, &jsonData)
- if err != nil {
- continue
- }
- m.ConversationID = conversationID
- m.SentAt = time.Unix(sentAtMs/1000, (sentAtMs%1000)*1000000)
- m.From = "Unknown"
+ var messages []map[string]interface{}
+ if err := json.Unmarshal(output, &messages); err != nil {
+ return mcp.NewToolError(fmt.Sprintf("Failed to parse conversation data: %v", err)), nil
+ }
- // Parse JSON data for attachments
- if jsonData.Valid && jsonData.String != "" {
+ result := fmt.Sprintf("Conversation %s (%d messages):\n\n", conversationID, len(messages))
+ for _, msg := range messages {
+ attachInfo := ""
+
+ // Check for attachments in JSON data
+ if jsonData, ok := msg["json"].(string); ok && jsonData != "" {
var rawJSON map[string]interface{}
- if err := json.Unmarshal([]byte(jsonData.String), &rawJSON); err == nil {
- m.RawJSON = rawJSON
- // Extract attachments if present
- if attachments, ok := rawJSON["attachments"].([]interface{}); ok {
- for _, att := range attachments {
- if attMap, ok := att.(map[string]interface{}); ok {
- attachment := Attachment{}
- if fileName, ok := attMap["fileName"].(string); ok {
- attachment.FileName = fileName
- }
- if path, ok := attMap["path"].(string); ok {
- attachment.Path = path
- }
- if contentType, ok := attMap["contentType"].(string); ok {
- attachment.ContentType = contentType
- }
- if size, ok := attMap["size"].(float64); ok {
- attachment.Size = int64(size)
- }
- m.Attachments = append(m.Attachments, attachment)
- }
- }
+ if err := json.Unmarshal([]byte(jsonData), &rawJSON); err == nil {
+ if attachments, ok := rawJSON["attachments"].([]interface{}); ok && len(attachments) > 0 {
+ attachInfo = fmt.Sprintf(" [%d attachments]", len(attachments))
}
}
}
- messages = append(messages, m)
- }
+ body := msg["body"]
+ if body == nil {
+ body = ""
+ }
- result := fmt.Sprintf("Conversation %s (%d messages):\n\n", conversationID, len(messages))
- for _, msg := range messages {
- attachInfo := ""
- if len(msg.Attachments) > 0 {
- attachInfo = fmt.Sprintf(" [%d attachments]", len(msg.Attachments))
+ if sentAt, ok := msg["sent_at"].(float64); ok {
+ t := time.Unix(int64(sentAt/1000), (int64(sentAt)%1000)*1000000)
+ result += fmt.Sprintf("%s: %s%s\n",
+ t.Format("2006-01-02 15:04"), body, attachInfo)
+ } else {
+ result += fmt.Sprintf("%s%s\n", body, attachInfo)
}
- result += fmt.Sprintf("%s: %s%s\n",
- msg.SentAt.Format("2006-01-02 15:04"), msg.Body, attachInfo)
}
return mcp.NewToolResult(mcp.NewTextContent(result)), nil
@@ -855,24 +817,36 @@ func (s *Server) handleListAttachments(req mcp.CallToolRequest) (mcp.CallToolRes
}
func (s *Server) handleGetStats(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
- if err := s.ensureConnection(); err != nil {
- return mcp.NewToolError(fmt.Sprintf("Database connection failed: %v", err)), nil
- }
-
- var totalMessages, totalConversations int
-
- // Get message count
- err := s.db.QueryRow("SELECT COUNT(*) FROM messages WHERE type NOT IN ('keychange', 'profile-change') AND type IS NOT NULL").Scan(&totalMessages)
+ // Get message count using command-line sqlcipher
+ messageQuery := "SELECT COUNT(*) as count FROM messages WHERE type NOT IN ('keychange', 'profile-change') AND type IS NOT NULL"
+ messageOutput, err := s.executeQuery(messageQuery)
if err != nil {
return mcp.NewToolError(fmt.Sprintf("Failed to count messages: %v", err)), nil
}
- // Get conversation count
- err = s.db.QueryRow("SELECT COUNT(*) FROM conversations WHERE type IS NOT NULL").Scan(&totalConversations)
+ var messageResult []map[string]interface{}
+ totalMessages := 0
+ if err := json.Unmarshal(messageOutput, &messageResult); err == nil && len(messageResult) > 0 {
+ if count, ok := messageResult[0]["count"].(float64); ok {
+ totalMessages = int(count)
+ }
+ }
+
+ // Get conversation count using command-line sqlcipher
+ convQuery := "SELECT COUNT(*) as count FROM conversations WHERE type IS NOT NULL"
+ convOutput, err := s.executeQuery(convQuery)
if err != nil {
return mcp.NewToolError(fmt.Sprintf("Failed to count conversations: %v", err)), nil
}
+ var convResult []map[string]interface{}
+ totalConversations := 0
+ if err := json.Unmarshal(convOutput, &convResult); err == nil && len(convResult) > 0 {
+ if count, ok := convResult[0]["count"].(float64); ok {
+ totalConversations = int(count)
+ }
+ }
+
result := fmt.Sprintf("Signal Database Statistics:\n- Total Messages: %d\n- Total Conversations: %d\n- Database Path: %s",
totalMessages, totalConversations, s.dbPath)