B4A=true Group=Default Group ModulesStructureVersion=1 Type=StaticCode Version=11 @EndOfDesignText@ 'Code module 'Subs in this code module will be accessible from all modules. Sub Process_Globals 'These global variables will be declared once when the application starts. 'These variables can be accessed from all modules. ' Public GZip As GZipStrings 'Usa la libreria CompressStrings Private su As StringUtils 'Usa la libreria StringUtils Dim phn As Phone Dim devModel As String Dim kmt, errorLog As SQL 'Requiere la libreria "SQL" 'ignore ' Dim wifi As MLwifi Dim ssid As String 'ignore ' Dim rutaInicioHoy As String = "" End Sub 'Pone el valor de phn.Model en la variable global "devModel" Sub getPhnId As String 'ignore 'Requiere la libreria "Phone" devModel = phn.Model If devModel.Length <= 3 Then 'Si phn.Model esta en blanco ... Dim t As String = phn.GetSettings("android_id") 'Intentamos con "android_id" devModel = t End If If devModel.Length >= 3 Then 'Si tenemos valor para phn.Model File.WriteString(File.DirInternal, "phnId.txt", devModel) 'Sobreescribimos archivo phnId.txt with deviceId ' Log("Tenemos phnId: "&devModel&" "&File.DirInternal&"/phn.txt sobreescrito") Else If devModel.Length < 3 Then ' Si no tenemos valor, lo leemos de phnId.txt Dim s As String = File.ReadString(File.DirInternal, "phnId.txt") devModel = s ' Log("Leemos id de "&File.DirInternal&"/phnId.txt") ' Log(devModel) End If Return devModel End Sub 'Comprime y regresa un texto (str) en base64 Sub compress(str As String) As String 'ignore 'Requiere la libreria "CompressStrings" ' Dim compressed() As Byte = GZip.compress(str) ' Dim base64 As String = su.EncodeBase64(compressed) ' Log($"Comprimido: ${base64.Length}"$) ' Return base64 End Sub 'Descomprime y regresa un texto en base64 Sub decompress(base64 As String) As String 'ignore Dim decompressedbytes() As Byte = su.DecodeBase64(base64) ' Log($"decompressedbytesLength: ${decompressedbytes.Length}"$) Dim bc As ByteConverter Dim uncompressed As String = bc.StringFromBytes(decompressedbytes,"UTF8") If Starter.logger Then Log($"Descomprimido: ${uncompressed.Length}"$) ' Log($"Decompressed String = ${uncompressed}"$) Return uncompressed End Sub 'Convierte una fecha al formato yyMMddHHmmss Sub fechaKMT(fecha As String) As String 'ignore ' Log(fecha) Dim OrigFormat As String = DateTime.DateFormat 'save orig date format DateTime.DateFormat="yyMMddHHmmss" Dim nuevaFecha As String=DateTime.Date(fecha) DateTime.DateFormat=OrigFormat 'return to orig date format ' Log(nuevaFecha) Return nuevaFecha End Sub 'Genera una notificacion con importancia alta Sub notiHigh(title As String, body As String, activity As Object) 'ignore Private notif As Notification notif.Initialize2(notif.IMPORTANCE_HIGH) notif.Icon = "icon" notif.Vibrate = False notif.Sound = False notif.AutoCancel = True If Starter.logger Then Log("notiHigh: "&title) notif.SetInfo(title, body, activity) ' Log("notiHigh SetInfo") notif.Notify(777) End Sub 'Regresa el objeto de una notificacion con importancia baja Sub notiLowReturn(title As String, Body As String, id As Int) As Notification 'ignore Private Notification As Notification Notification.Initialize2(Notification.IMPORTANCE_LOW) If Starter.logger Then Log("notiLowReturn: "&title) Notification.Icon = "icon" Notification.Sound = False Notification.Vibrate = False Notification.SetInfo(title, Body, Main) Notification.Notify(id) ' Log("notiLowReturn SetInfo") Return Notification End Sub 'Escribimos las coordenadas y fecha a un archivo de texto Sub guardaInfoEnArchivo(coords As String) 'ignore ' Cambiamos el formato de la hora Dim OrigFormat As String=DateTime.DateFormat 'save orig date format DateTime.DateFormat="MMM-dd HH:mm:ss" Dim lastUpdate As String=DateTime.Date(DateTime.Now) DateTime.DateFormat=OrigFormat 'return to orig date format Dim ubic As String = coords&","&lastUpdate Dim out As OutputStream = File.OpenOutput(File.DirRootExternal, "gps.txt", True) Dim s As String = ubic & CRLF Dim t() As Byte = s.GetBytes("UTF-8") out.WriteBytes(t, 0, t.Length) out.Close End Sub 'Escribimos las coordenadas (latitud, longitud, fecha) y fecha a una BD Sub guardaInfoEnBD(coords As String) 'ignore If Starter.logger Then Log("Guardamos ubicacion en BD - "&coords) Try Dim latlon() As String = Regex.Split("\|", coords) If latlon.Length < 2 Then latlon = Regex.Split(",", coords) 'Si son menos de 2, entonces estan separadas por comas y no por "|" ' If Main.Logger Then Log("LatLon="&latlon) If Not(kmt.IsInitialized) Then revisaBD kmt.ExecNonQuery2("INSERT INTO RUTA_GPS(fecha, lat, lon) VALUES (?,?,?)", Array As Object (latlon(2),latlon(0),latlon(1))) Catch Log(LastException) End Try End Sub 'Limpiamos la tabla RUTA_GPS de la BD Sub deleteGPS_DB 'ignore kmt.ExecNonQuery("delete from RUTA_GPS") kmt.ExecNonQuery("vacuum;") End Sub 'Limpiamos la tabla errorLog de la BD Sub deleteErrorLog_DB 'ignore If Not(errorLog.IsInitialized) Then revisaBD errorLog.ExecNonQuery("delete from errores") errorLog.ExecNonQuery("vacuum;") ' ToastMessageShow("Borrada", False) End Sub 'Borramos el archio "gps.txt" Sub borramosArchivoGPS 'ignore Dim out As OutputStream = File.OpenOutput(File.DirRootExternal, "gps.txt", False) Dim s As String = "" Dim t() As Byte = s.GetBytes("UTF-8") out.WriteBytes(t, 0, t.Length) out.Close End Sub 'Revisa que exista la BD y si es necesario crea algunas tablas dentro de ella Sub revisaBD 'ignore ' Log("subs.revisaBD") Starter.ruta = File.DirInternal If Not(Starter.colaNotifs.IsInitialized) Then Starter.colaNotifs.Initialize(Starter.ruta, "colaNotifs.db", True) Starter.colaNotifs.ExecNonQuery("CREATE TABLE If Not EXISTS cola (id INTEGER UNIQUE, numero TEXT, contestada INTEGER, timestamp INTEGER, PRIMARY KEY(id AUTOINCREMENT))") 'Tabla para la reglas If Not(Starter.reglasDB.IsInitialized) Then Starter.reglasDB.Initialize(Starter.ruta, "bow.db", True) If Starter.logger Then LogColor("========"&Starter.ruta, Colors.Red) Starter.reglasDB.ExecNonQuery("CREATE TABLE If Not EXISTS reglas (id INTEGER UNIQUE, nombre TEXT, activa INTEGER, recibe TEXT, contesta TEXT, destinatario TEXT, contactosSI TEXT, PRIMARY KEY(id AUTOINCREMENT))") 'Tabla para las imagenes Starter.reglasDB.ExecNonQuery("CREATE TABLE If Not EXISTS datosImg (message_row_id INTEGER, chat_row_id INTEGER, autotransfer_retry_enabled INTEGER, media_job_uuid TEXT, transferred INTEGER, transcoded INTEGER, file_path TEXT, file_size INTEGER, suspicious_content INTEGER, trim_from INTEGER, trim_to INTEGER, face_x INTEGER, face_y INTEGER, media_key_timestamp INTEGER, width INTEGER, height INTEGER, has_streaming_sidecar INTEGER, gif_attribution INTEGER, thumbnail_height_width_ratio REAL, first_scan_length INTEGER, file_length INTEGER, media_name TEXT, file_hash TEXT, media_duration INTEGER, page_count INTEGER, enc_file_hash TEXT, is_animated_sticker INTEGER, mute_video INTEGER)") Starter.reglasDB.ExecNonQuery("CREATE TABLE If Not EXISTS datosMsj (_id INTEGER, key_remote_jid TEXT, key_from_me INTEGER, key_id TEXT, status INTEGER, needs_push INTEGER, timestamp INTEGER, media_wa_type TEXT, media_size INTEGER, media_name TEXT, media_caption TEXT, media_hash TEXT, media_duration INTEGER, origin INTEGER, latitude REAL, longitude REAL, thumb_image TEXT, received_timestamp INTEGER, send_timestamp INTEGER, receipt_server_timestamp INTEGER, receipt_device_timestamp INTEGER, recipient_count INTEGER, quoted_row_id INTEGER, edit_version INTEGER, media_enc_hash TEXT, forwarded INTEGER, preview_type INTEGER, lookup_tables INTEGER, future_message_type INTEGER, message_add_on_flags INTEGER)") 'Tabla para la notificaciones If Not(Starter.historicoDB.IsInitialized) Then Starter.historicoDB.Initialize(Starter.ruta, "historicoDB.db", True) Starter.historicoDB.ExecNonQuery("CREATE TABLE If Not EXISTS historico (id INTEGER UNIQUE, numero TEXT, nombre TEXT, regla TEXT, mensaje TEXT, E_S TEXT, clic TEXT, fecha TEXT, PRIMARY KEY(id AUTOINCREMENT))") 'Tabla para la bitacora de errores If Not(errorLog.IsInitialized) Then errorLog.Initialize(Starter.ruta, "errores.db", True) errorLog.ExecNonQuery("CREATE TABLE IF NOT EXISTS errores(fecha INTEGER, error TEXT)") Try 'Intentamos usar "pragma_table_info" para revisar si existe la columna "numero" en la tabla Dim c As Cursor=Starter.historicoDB.ExecQuery("SELECT COUNT(*) AS fCol FROM pragma_table_info('historico') WHERE name='numero'") c.Position = 0 If c.GetString("fCol") = 0 Then 'Si no esta la columna FECHA la agregamos Starter.historicoDB.ExecNonQuery("ALTER TABLE historico ADD COLUMN numero TEXT") End If Catch 'Si no funciona "pragma_table_info" lo hacemos con try/catch Try Starter.historicoDB.ExecNonQuery("ALTER TABLE historico ADD COLUMN numero TEXT") Catch Log(LastException) End Try End Try Try 'Intentamos usar "pragma_table_info" para revisar si existe la columna "regla" en la tabla Dim c As Cursor=Starter.historicoDB.ExecQuery("SELECT COUNT(*) AS fCol FROM pragma_table_info('historico') WHERE name='regla'") c.Position = 0 If c.GetString("fCol") = 0 Then 'Si no esta la columna FECHA la agregamos Starter.historicoDB.ExecNonQuery("ALTER TABLE historico ADD COLUMN regla TEXT") End If Catch 'Si no funciona "pragma_table_info" lo hacemos con try/catch Try Starter.historicoDB.ExecNonQuery("ALTER TABLE historico ADD COLUMN regla TEXT") Catch Log(LastException) End Try End Try End Sub 'Obtiene el ssid al que esta conectado el telefono Sub getSSID 'ignore ' 'Requiere la libreria "MLWifi400" ' If wifi.isWifiConnected Then ' ssid = wifi.WifiSSID ' End If End Sub 'Convierte un texto en formato JSON a un objeto "Map" Sub JSON2Map(theJson As String) As Map 'ignore 'Requiere la libreria "JSON" Try Private json As JSONParser json.Initialize(theJson) Return json.NextObject Catch Log(LastException) log2DB("JSON2Map: "&LastException) Private m As Map = CreateMap("title":"Error generating JSON", "t":"Error", "Message":LastException, "text" : LastException) Return m End Try End Sub 'Convierte un mapa a formato JSON Sub map2JSON(m As Map) As String 'ignore 'Requiere la libreria "JSON" 'Convierte un objecto "Map" a JSON Dim jg As JSONGenerator jg.Initialize(m) Dim t As String = jg.ToString Return t End Sub 'Mandamos "coords" en un mensaje a "Sprvsr" Sub mandamosLoc(coords As String) 'ignore '' Log("Iniciamos mandamosLoc "&coords) '' Log("locRequest="&Tracker.locRequest) ' guardaInfoEnBD(coords)'Escribimos coordenadas y fecha a una bd ' Dim t As String ' If Tracker.locRequest="Activa" Then ' If PushService.au = 1 Then ' t = "au" ' es una actualizacion ' Else ' t = "u" ' es una peticion ' End If ' Dim params As Map = CreateMap("topic":"Sprvsr", "coords":coords, "t":t, "b":PushService.battery) ' CallSub2(PushService, "mandaMensaje",params) ' Tracker.locRequest="Enviada" ' CallSubDelayed(Tracker,"CreateLocationRequest") ' End If End Sub 'Regresa la fecha y hora de hoy a las 00:00 en el formato "yyMMddHHMMSS" Sub fechaInicioHoy As String 'ignore Dim OrigFormat As String = DateTime.DateFormat 'save orig date format DateTime.DateFormat="yyMMdd" Private h As String = DateTime.Date(DateTime.Now)&"000000" DateTime.DateFormat=OrigFormat 'return to orig date format If Starter.logger Then Log("Hoy="&h) Return h End Sub 'Guardamos "texto" a la bitacora Sub log2DB(texto As String) 'ignore LogColor(fechaKMT(DateTime.Now)&" - log2BD: '"&texto&"'", Colors.Magenta) If kmt.IsInitialized Then kmt.ExecNonQuery2("INSERT INTO bitacora(fecha, texto) VALUES (?,?)", Array As Object (fechaKMT(DateTime.now), texto)) End Sub 'Regresa verdadero si ya pasaron XX minutos de la fecha dada Sub masDeXXMins(hora As Int, mins As Int) As Boolean 'ignore If (hora + mins * DateTime.TicksPerMinute) < DateTime.Now Then Return True Else Return False End If End Sub 'Regresa verdadero si ya pasaron XX minutos de la fechaKMT dada Sub masDeXXMinsKMT(hora As String, mins As Int) As Boolean 'ignore Try ' LogColor($"Hora=${fechaKMT(fechaKMT2Ticks(hora) + mins * DateTime.TicksPerMinute)}, Mins=${mins}, Actual=${fechaKMT(DateTime.Now)}"$,Colors.red) If fechaKMT2Ticks(hora) + mins * DateTime.TicksPerMinute < DateTime.Now Then ' Log("+++ +++ "&fechaKMT(fechaKMT2Ticks(hora) + mins * DateTime.TicksPerMinute) & " < " & fechaKMT(DateTime.Now)) Return True Else ' Log("+++ +++ "&fechaKMT(fechaKMT2Ticks(hora) + mins * DateTime.TicksPerMinute) & " > " & fechaKMT(DateTime.Now)) Return False End If Catch Log(LastException) End Try End Sub 'Limpiamos la tabla "bitacora" de la BD Sub borraLogDB 'ignore If Starter.logger Then LogColor("Borramos BD de log", Colors.Magenta) kmt.ExecNonQuery("delete from bitacora") kmt.ExecNonQuery("vacuum;") End Sub 'Borramos renglones extra de la tabla de errores Sub borraArribaDe100Errores 'ignore If Not(errorLog.IsInitialized) Then revisaBD If Starter.logger Then LogColor("Recortamos la tabla de Errores, limite de 100", Colors.Magenta) errorLog.ExecNonQuery("DELETE FROM errores WHERE fecha NOT in (SELECT fecha FROM errores ORDER BY fecha desc LIMIT 99 )") errorLog.ExecNonQuery("vacuum;") ' Log("Borramos mas de 100 de errorLog") End Sub 'Borramos renglones extra de la tabla de bitacora Sub borraArribaDe600RenglonesBitacora 'ignore revisaBD If Starter.logger Then LogColor("Recortamos la tabla de la Bitacora, limite de 600", Colors.Magenta) Private c As Cursor c = kmt.ExecQuery("select fecha from bitacora") c.Position = 0 If c.RowCount > 650 Then kmt.ExecNonQuery("DELETE FROM bitacora WHERE fecha NOT in (SELECT fecha FROM bitacora ORDER BY fecha desc LIMIT 599 )") kmt.ExecNonQuery("vacuum;") ' Log("Borramos mas de 600 de bitacora") End If c.Close End Sub 'Inserta 50 renglones de prueba a la tabla "errores" Sub insertaRenglonesPruebaEnErrorLog 'ignore If Not(errorLog.IsInitialized) Then revisaBD If Starter.logger Then Log("insertamos 50 renglones a errorLog") For x = 1 To 50 errorLog.ExecNonQuery2("INSERT INTO errores(fecha, error) VALUES (?,?)", Array As Object (fechaKMT(DateTime.now), "abc")) If Starter.logger Then Log(x) Next End Sub 'Regresa la tabla "errores" en una lista de mapas convertida a JSON Sub dameErroresJSON(SQL As SQL, maxErrores As Int, comprimido As Boolean) As String 'ignore If Starter.logger Then Log("dameErroresJSON") Private j As JSONGenerator Private lim As String Private cur As ResultSet Private l As List Private i As Int = 0 l.Initialize Dim m, m2 As Map m2.Initialize If maxErrores = 0 Then lim = "" Else lim = "limit "&maxErrores cur = SQL.ExecQuery("select * from errores order by fecha desc "&lim) Do While cur.NextRow m.Initialize m.Put("fecha", cur.GetString("fecha")) m.Put("error", cur.GetString("error")) m2.Put(i,m) i = i + 1 Loop cur.Close j.Initialize(m2) Log(j.ToString) If comprimido Then Return compress(j.ToString) Else Return j.ToString End If End Sub 'Convierte una fecha en formato YYMMDDHHMMSS a Ticks Sub fechaKMT2Ticks(fKMT As String) As Long 'ignore Try If fKMT.Length = 12 Then Private parteFecha As String = fKMT.SubString2(0,6) Private parteHora As String = fKMT.SubString(6) Private OrigFormat As String = DateTime.DateFormat 'save original date format DateTime.DateFormat="yyMMdd" DateTime.TimeFormat="HHmmss" Private ticks As Long = DateTime.DateTimeParse(parteFecha,parteHora) ' Log(" +++ +++ pFecha:"&parteFecha&" | pHora:"&parteHora) DateTime.DateFormat=OrigFormat 'return to original date format Return ticks Else If Starter.logger Then Log("Formato de fecha incorrecto, debe de ser 'yyMMddHHmmss', no '"&fKMT&"' largo="&fKMT.Length) Return 0 End If Catch Log(LastException) If Starter.logger Then LogColor($"Fecha dada: ${fKMT}, Parte Fecha: ${parteFecha}, Parte Hora: ${parteHora}"$, Colors.Red) Return 0 End Try End Sub Sub InstallAPK(dir As String, apk As String) 'ignore ' If File.Exists(dir, apk) Then ' Dim i As Intent ' i.Initialize(i.ACTION_VIEW, "file://" & File.Combine(dir, apk)) ' i.SetType("application/vnd.android.package-archive") ' StartActivity(i) ' End If End Sub 'Hace visible el panel con los parametros "Top" y "Left" dados Sub panelVisible(panel As Panel, top As Int, left As Int) 'ignore panel.BringToFront panel.Visible = True panel.Top = top panel.Left = left End Sub 'Oculta el panel especificado y lo manda al fondo Sub panelOculto(panel As Panel) 'ignore panel.SendToBack panel.Visible = False End Sub 'Centra una etiqueta dentro de un elemento superior Sub centraEtiqueta(elemento As Label, anchoElementoSuperior As Int) 'ignore elemento.Left = Round(anchoElementoSuperior/2)-(elemento.Width/2) End Sub 'Centra un panel dentro de un elemento superior Sub centraPanel(elemento As Panel, anchoElementoSuperior As Int) 'ignore elemento.Left = Round(anchoElementoSuperior/2)-(elemento.Width/2) End Sub 'Centra una barra de progreso dentro de un elemento superior Sub centraProgressBar(elemento As ProgressBar, anchoElementoSuperior As Int) 'ignore elemento.Left = Round(anchoElementoSuperior/2)-(elemento.Width/2) End Sub Sub insertaEnErrores(error As String) 'ignore If Not(errorLog.IsInitialized) Then revisaBD errorLog.ExecNonQuery2("INSERT INTO errores(fecha, error) VALUES (?,?)", Array As Object (fechaKMT(DateTime.now), error)) End Sub 'Cierra todas las actividades y sale de la aplicacion (Android 4.1+ - API 16+) Sub cierraActividades 'ignore If Starter.logger Then Log("closing activities") Dim jo As JavaObject jo.InitializeContext jo.RunMethod("finishAffinity", Null) End Sub 'Regresa un mapa con las reglas. Sub traeReglas As Map If Starter.logger Then LogColor("Traemos reglas de BD", Colors.Magenta) Private mReglas As Map mReglas.Initialize Private c As Cursor ' c=Starter.reglasDB.ExecQuery("select * from reglas order by nombre") c=Starter.reglasDB.ExecQuery("Select *, SUBSTR(nombre, (INSTR(nombre, '_')+1), (LENGTH(nombre)-INSTR(nombre, '_'))) as ord FROM reglas order by ord") 'Este query trae las reglas ordenadas por "nombre" que tienen texto como "1.1.2, 10.2.1, 13.1" If c.RowCount > 0 Then Private mr As Map For i=0 To c.RowCount -1 c.Position = i Private contactosSI As String = c.GetString("contactosSI") If contactosSI = Null Then contactosSI = "" mr = CreateMap("activa":c.GetInt("activa"), "recibe":c.GetString("recibe"), "contesta":c.GetString("contesta"), "id":c.GetInt("id"), "nombre":c.GetString("nombre"), "destinatario":c.GetString("destinatario"), "contactoEspecifico":contactosSI) mReglas.Put(c.GetInt("id"), mr) Next End If c.Close ' LogColor("mReglas=" & mReglas, Colors.Blue) Return mReglas End Sub 'Activa o desactiva la regla especificada. Sub guardaRegla(id As Int, activa As Boolean) ' Private c As Cursor Private act As Int = 0 If activa Then act = 1 If Starter.logger Then Log("Guardamos regla " & id) If Starter.logger Then Log($"update reglas set activa=${act} where id=${id}"$) Starter.reglasDB.ExecNonQuery($"update reglas set activa=${act} where id=${id}"$) End Sub 'Agrega una regla en blanco y descativada a la base de datos. Sub agregaRegla Starter.reglasDB.ExecNonQuery("insert into reglas (activa, recibe, contesta) values (0, '', '')") Dim c As Cursor c=Starter.reglasDB.ExecQuery("select last_insert_rowid() as ultimo from reglas") 'Traemos el id de la ultima regla agregada. If c.RowCount > 0 Then c.Position = 0 Starter.reglasDB.ExecNonQuery($"update reglas set nombre = ${c.GetInt("ultimo")} where id = ${c.GetInt("ultimo")}"$) 'Y lo ponemos en el nombre. End If End Sub 'Borra una regla de la base de datos. Sub borrarRegla (id As Int) Starter.reglasDB.ExecNonQuery($"delete from reglas where id=${id}"$) Starter.reglasDB.ExecNonQuery("delete from sqlite_sequence where name='reglas'") Starter.reglasDB.ExecNonQuery("vacuum;") End Sub 'Guarda el objeto de la notificacion en un mapa y en la cola de notificaciones por contestar. Sub guardaNotificacion(sbn As StatusBarNotification) 'ignore If Starter.logger Then Log("guardaNotificacion=" & sbn.Title & " - " & sbn.Message) Private noti As lasNotis noti.Initialize noti.numero = sbn.Title noti.notif = sbn Dim titulo As String = sbn.Title If isGroupWA(sbn) Then titulo = getGroupName2(sbn) Private tempMap As Map tempMap.Initialize Private timestamp = DateTime.Now tempMap.Put(titulo, noti) NotificationService.notisMap2.Put(titulo, tempMap) Starter.notismap2 = NotificationService.notisMap2 NotificationService.notificacionesPorContestar.Add(tempMap)'Tambien lo agregamos a la cola de notificaciones por contestar. If Starter.logger Then LogColor("======== Notificaciones pendientes:" & NotificationService.notificacionesPorContestar.Size & "=============", Colors.Magenta) ' LogColor("Cola de notificaciones="&NotificationService.notificacionesPorContestar, Colors.RGB(168,0,0)) End Sub 'Searches the provided notification object for the string "@g.us" and if found returns TRUE. Sub isGroupWA(sbn As StatusBarNotification) As Boolean Private a As Boolean = False If sbn.As(String).IndexOf("@g.us") > -1 Then a = True 'ignore Return a End Sub 'Returns the name of the group from the given notification object. 'Searches the provided notification for the string "hiddenConversationTitle" and if found, gets the name. 'If it is not a group returns the notification's title. Sub getGroupName2(sbn As StatusBarNotification) As String Private inicio As Int = sbn.Extras.As(String).IndexOf("hiddenConversationTitle=") 'ignore If inicio > -1 And sbn.Extras.As(String).IndexOf("hiddenConversationTitle=null") = -1 Then 'ignore Private x As String = sbn.Extras.As(String) 'ignore Private fin As Int = x.IndexOf(", android.reduced.images=") x = x.SubString2(inicio+24, fin) x = Regex.Replace(" \(.+\)", x, "") 'Replace anything between () with "", this en the case that we have something like "MyGroupName (5 messages)" Else 'Is not from a group. Private x As String = sbn.Title End If Return x End Sub 'Guarda la ultima regla que se haya cumplido y el número que la mandó. Sub guardaUltimaRegla(sbn As StatusBarNotification, regla As String) 'ignore Private numRemitente As String = getNumberWA(sbn) If numRemitente = "Not a person" Then numRemitente = getGroupName(sbn.Title) Private tmpMap As Map tmpMap.Initialize If NotificationService.histReglas.ContainsKey(numRemitente) Then tmpMap = NotificationService.histReglas.Get(numRemitente) ' Log("+++++++++++++++++++++++++++++++++++++++++++") ' Log(numRemitente) ' LogColor("histReglas="&NotificationService.histReglas,Colors.Blue) ' Log(regla) ' Log("tmpMap="&tmpMap) Private tmpList, tmpList2 As List tmpList.Initialize tmpList2.Initialize If tmpMap.ContainsKey("historico") Then tmpList = tmpMap.Get("historico") If tmpMap.ContainsKey("histReglas") Then tmpList2 = tmpMap.Get("histReglas") ' Log(regla) Private ur As String = "" If tmpList.Size > 0 And tmpList.Get(0).As(Map).Size > 0 Then ur = tmpList.Get(0).As(Map).Get("regla") ' Log("Regla anterior: "&ur) ' LogColor(tmpList, Colors.red) Private tm As Map = CreateMap("regla":regla, "mensaje":sbn.Message, "anterior":ur, "numero":numRemitente) tmpList2.InsertAt(0, regla) ' LogColor("ponemos en historico:"&tm, Colors.Magenta) tmpList.InsertAt(0, tm) ' Log(tm) tmpMap = CreateMap("histReglas":tmpList2, "historico":tmpList, "numero":numRemitente) ' Log(tmpMap) NotificationService.histReglas.Put(numRemitente, tmpMap) ' Starter.ultimaReglaCumplida.Put(numRemitente, tmpMap) ' Log(NotificationService.histReglas) ' Log("+++++++++++++++++++++++++++++++++++++++++++++") ' For i = 0 To tmpList.Size -1 ' Log(tmpList.Get(i)) ' Next ' Log("histReglas="&NotificationService.histReglas) End Sub 'Manda el procesamiento de la siguiente regla a la regla especificada. Sub vamosA( sbn As StatusBarNotification, regla As String) Private numRemitente As String = getNumberWA(sbn) If numRemitente = "Not a person" Then numRemitente = getGroupName(sbn.Title) Private tmpMap As Map tmpMap.Initialize If NotificationService.histReglas.ContainsKey(numRemitente) Then tmpMap = NotificationService.histReglas.Get(numRemitente) Private tmpList, tmpList2 As List tmpList.Initialize tmpList2.Initialize If tmpMap.ContainsKey("historico") Then tmpList = tmpMap.Get("historico") If tmpMap.ContainsKey("histReglas") Then tmpList2 = tmpMap.Get("histReglas") If Starter.logger Then Log(regla) Private ur As String = "" 'ignore If tmpList.Size > 0 And tmpList.Get(0).As(Map).Size > 0 Then ur = tmpList.Get(0).As(Map).Get("regla") ' Log("Regla anterior: "&ur) ' Private tm As Map = CreateMap("regla":regla, "mensaje":sbn.Message, "anterior":ur, "numero":numRemitente) 'ignore tmpList2.InsertAt(0, regla) ' LogColor("ponemos en historico:"&tm, Colors.Magenta) ' tmpList.InsertAt(0, tm) tmpMap = CreateMap("histReglas":tmpList2, "historico":tmpList, "numero":numRemitente) NotificationService.histReglas.Put(numRemitente, tmpMap) If Starter.logger Then Log("histReglas="&NotificationService.histReglas) End Sub 'Returns the sender's number. 'Searches the provided notification object and gets the numbers between "shortcut=" and "@s.whatsapp.net". Sub getNumberWA(sbn As StatusBarNotification) As String Private a As Int = sbn.As(String).IndexOf("@s.whatsapp.net") 'ignore If a > -1 Then Private x As String = sbn.As(String) 'ignore Private y As Int = x.IndexOf("shortcut=") x = x.SubString2(y+9, a) Else 'It is probably is a group. x = "Not a person" End If Return x End Sub 'Returns the name of the group from the given text. 'If it is not a group, then returns the notification's title. Sub getGroupName(sbnTitle As String) As String 'ignore Private a As Int = sbnTitle.IndexOf(": ") Private x As String = sbnTitle If a > -1 Then Private b As String = sbnTitle.SubString2(0, a) x = Regex.Replace(" \(.+\)", b, "") End If Return x End Sub 'Copia la base de datos de las reglas a la tarjeta de memoria. Sub copiaDB Private theDir As String = "" Try File.MakeDir(File.DirRootExternal, "Bow2.0") theDir = "/Bow2.0" Catch theDir = "" End Try If Starter.logger Then Log($"Origen:${Starter.ruta}, destino:${File.DirRootExternal}"$) Try File.Copy(File.DirInternal,"bow.db",File.DirRootExternal&theDir,"bow.db") File.Copy(File.DirInternal,"historicoDB.db",File.DirRootExternal&theDir,"historicoDB.db") ToastMessageShow("Listo, copiado a " & File.DirRootExternal&theDir & "/bow.db", False) Catch ToastMessageShow("No se pudo hacer la copia: "&LastException, True) End Try End Sub 'Actualiza una regla modificada. Sub actualizaRegla(id As Int, nombre As String, recibe As String, contesta As String, destinatario As String, contactosSI As String) Starter.reglasDB.ExecNonQuery2("update reglas set nombre = ?, recibe = ?, contesta = ?, destinatario = ?, contactosSI = ? where id = ?", Array As Object(nombre, recibe, contesta, destinatario, contactosSI, id)) If Starter.logger Then Log($"========== ${nombre}, ${recibe}, ${contesta}, ${id}, ${destinatario}, ${contactosSI}"$) If Starter.logger Then Log("Guardado") End Sub 'Regresa el "shortcut" del remitente. 'Si es de un grupo es algo como "120363023512345678@g.us" 'Si es de una persona entonces "5215512345678@s.whatsapp.net" Sub getShortcut(sbn As StatusBarNotification) As String Private x As String = sbn.As(String) 'ignore Private ap As Int = x.IndexOf("@s.whatsapp.net") 'ignore Private ag As Int = x.IndexOf("@g.us") 'ignore Private sc As Int = x.IndexOf("shortcut=") If x.IndexOf("Notification(channel=group") = -1 And x.IndexOf("Notification(channel=individual") = -1 And x.IndexOf("Notification(channel=silent") = -1 Then 'En algunos casos el "channel" trae el "shortcut" y estorba para en "indexOf". sc = x.IndexOf("channel=") - 1 End If If Starter.logger Then LogColor(x, Colors.red) If ap > -1 Then Private x As String = sbn.As(String) 'ignore If Starter.logger Then Log($"x:${x}, y:${sc}, ag:${ap}"$) x = x.SubString2(sc+9, ap+15) Else if ag > -1 Then 'It is probably is a group. Private x As String = sbn.As(String) 'ignore If Starter.logger Then Log($"x:${x}, y:${sc}, ag:${ag}"$) x = x.SubString2(sc+9, ag+5) End If Return x End Sub 'Abre Whatsapp en el chat especificado. Sub abreWAChat(chat As String) ' Dim num As String = "5215554192439@s.whatsapp.net" ' Dim grupo As String = "120363022847621622@g.us" Dim i As Intent i.Initialize("android.intent.action.SEND", "") i.SetType("text/plain") i.PutExtra("android.intent.extra.TEXT", " ") i.PutExtra("jid", chat) i.SetPackage("com.whatsapp") StartActivity(i) End Sub 'Regresa el numero de veces que aparece un caracter en la cadena dada. 'Esta funcion la ocupo para reconocer las reglas que dependen de otras (Submenus). Sub CountChars(text As String, substr As String) As Int Dim t As String = text.Replace(substr, "") Return text.Length - t.Length End Sub 'Change CheckBox colors Sub SetButtonTintList(View As View, Disabled As Int, Enabled As Int) Dim States(2,1) As Int Dim sd As StateListDrawable 'ignore States(0, 0) = sd.State_Enabled States(1, 0) = sd.State_Disabled Dim Color(2) As Int = Array As Int(Enabled, Disabled) Dim CSL As JavaObject CSL.InitializeNewInstance("android.content.res.ColorStateList",Array(States,Color)) Dim jo As JavaObject jo.InitializeStatic("android.support.v4.widget.CompoundButtonCompat") jo.RunMethod("setButtonTintList", Array(View, CSL)) End Sub 'Regresa una lista con los nombres de los contactos del telefono. Sub getContactos As List Dim cr As ContentResolver cr.Initialize("cr") Private PeopleProjection() As String = Array As String("display_name") Private l As List l.Initialize Dim u As Uri u.Parse("content://com.android.contacts/contacts") Dim c As Cursor = cr.Query(u, PeopleProjection, "", Null, "display_name") For i = 0 To c.RowCount - 1 c.Position = i ' Log($"${c.GetString("display_name")}"$) l.Add(c.GetString("display_name")) Next c.Close Return l End Sub 'Remove duplicates from a list. 'Returns the list without duplicates. Sub removeListDuplicates(pList As List) As List If pList = Null Or Not(pList.IsInitialized) Then Return pList If Starter.logger Then Log(pList) Dim lstNew As List : lstNew.Initialize Dim objItem As Object For i = 0 To pList.Size - 1 objItem = pList.Get(i) If lstNew.IndexOf(objItem) = - 1 Then lstNew.Add(objItem) End If Next If Starter.logger Then Log(lstNew) Return lstNew End Sub 'Manda un mensaje al número especificado (+52 55 XXXX XXXX) mediante un objeto SBN (StatusBarNotification). 'Es necesario que se haya recibido previamente un mensaje del numero especificado. Sub mandaWAMsjSBN(numero As String, mensaje As String) 'ignore If numero = Null Then numero = "+52 55 5419 2439" Dim tempMap As Map = NotificationService.notisMap2.Get(numero) If tempMap.IsInitialized Then Dim t1 As lasNotis = tempMap.Get(numero) Dim t2 As StatusBarNotification = t1.notif If t2.IsInitialized Then NotificationService.rp.reply(t2.Notification, t2.PackageName, mensaje) CallSubDelayed3(NotificationService, "guardaMsjSalida", t2, mensaje) End If Else ToastMessageShow($"No hay notificaciones de ${numero}"$, False) End If End Sub 'Converts an image to a bytes array (for BLOB fields). Public Sub ImageToBytes(Image As Bitmap) As Byte() Dim out As OutputStream out.InitializeToBytesArray(0) Image.WriteToStream(out, 100, "JPEG") out.Close Return out.ToBytesArray End Sub 'Manda un mensaje al número especificado (52155XXXXXXXX) mediante un script de shell y root. 'El celular necesita estar rooteado. 'El destinatario debe tener la lada completa sin signos de mas, es decir, para mexico 521 + el numero a 10 digitos. Sub mandaWAMsjRoot(mensaje As String, destinatario As String) 'ignore Private waPackage As String = "com.whatsapp" Dim Command, Runner As String Dim StdOut, StdErr As StringBuilder StdOut.Initialize StdErr.Initialize Dim Result As Int Dim Ph As Phone Private jid As String = $"${destinatario}@s.whatsapp.net"$ Private key_id As String = $"${DateTime.Now}-1"$ Private mensaje As String = $"/msjTest ${mensaje} ${DateTime.Time(DateTime.Now)}"$ Private received_timestamp As String = "0" ' Log(key_id) ' ******************************************************************************************* ' ******************************************************************************************* ' Hay que revisar que el numero del destinatario exista en la tabla "jid.user" y si no existe, entonces agregarlo: ' user server Agent Type raw_string device ' 5215554192439 s.whatsapp.net 0 0 5215554192439@s.whatsapp.net 0 ' Hay que agregar en la tabla "chat": ' - el renglon correspondiente de la tabla "jid" (_id) en "jid_row_id". ' - el renglon correspondiente de la tabla "messages" (_id) en "display_message_row_id". ' - y mas columnas ... 'Revisamos que exista el numero al que vamos a mandar el mensaje en la tabla "jid". Private jids As String = hazRootQuery($"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'select _id from jid where user = "${destinatario}" limit 1';"$, "getNumber") ' Log($"|${jids.trim}|"$) If jids.Trim = "" Then 'Si no existe, entonces lo insertamos. If Starter.logger Then LogColor("No hay JID, lo insertamos", Colors.Red) Private sqlInsertJid As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'INSERT INTO jid (user, server, Agent, Type, raw_string, device) VALUES ("${destinatario}", "s.whatsapp.net", 0, 0, "${jid}", 0)';"$ hazRootQuery(sqlInsertJid, "InsertJid") 'Insertamos el numero en la tabla "jid". End If 'Traemos el jid insertado. Private elJid As String = hazRootQuery($"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'SELECT _id FROM jid where user = "${destinatario}" limit 1';"$, "GetJid") elJid = elJid.trim ' Log("****** "&elJid) ' ******************************************************************************************* ' Agregamos el mensaje a la tabla "messages". ' ******************************************************************************************* Private suCmd As String = $"sqlite3 /data/data/com.whatsapp/databases/msgstore.db 'INSERT INTO messages (key_remote_jid,key_from_me,key_id,status,needs_push,data,timestamp,media_url,media_mime_type,media_wa_type,media_size,media_name,media_hash,latitude,longitude,thumb_image,remote_resource,received_timestamp,send_timestamp,receipt_server_timestamp,receipt_device_timestamp,raw_data,recipient_count,media_duration,origin) VALUES ("${jid}", 1, "${key_id}",0,0,"${mensaje}",${key_id},"","",0,0,"","",0,0,"","",${received_timestamp},-1,-1,-1,"",0,0,0)';"$ ' Private suCmd As String = $"sqlite3 /data/data/com.gbwhatsapp/databases/msgstore.db 'SELECT _id, key_remote_jid, data FROM messages WHERE data like "Test%"';"$ Runner = File.Combine(File.DirInternalCache, "runner") Command = File.Combine(File.DirInternalCache, "command") File.WriteString(File.DirInternalCache, "runner", "su < " & Command) File.WriteString(File.DirInternalCache, "command", suCmd & CRLF & "exit") 'Any commands via crlf, and exit at end Result = Ph.Shell("sh", Array As String(Runner), StdOut, StdErr) ' Log(Result) If Result = 0 Then ToastMessageShow("Mensaje enviado", False) 'Traemos el id del ultimo mensaje de la tabla "messages". Private lastMsgId As Int = hazRootQuery($"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'SELECT max(_id) FROM messages';"$, "GetLastMsgId") ' Log(lastMsgId) 'Revisamos si existe el jid en la tabla "chat". Private chatJid As String = hazRootQuery($"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'select count(jid_row_id) from chat where jid_row_id = "${elJid}"';"$, "getChatJid") ' Log($"|${chatJid.trim}|"$) If chatJid.Trim > 0 Then 'Actualizamos los datos necesarios en la tabla "chat". Private sqlUpdateChat As String = hazRootQuery($"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'update chat set hidden = 0, display_message_row_id = ${lastMsgId}, last_message_row_id = ${lastMsgId}, last_read_message_row_id = ${lastMsgId}, last_read_receipt_sent_message_row_id = ${(lastMsgId-1)}, last_important_message_row_id = 1, archived = 0, sort_timestamp = ${DateTime.Now} where jid_row_id = ${elJid}';"$, "updateChat") ' Log("Actualizamos en CHAT") Else 'Insertamos los datos necesarios a la tabla "chat" Private sqlInsertChat As String = hazRootQuery($"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'insert into chat (jid_row_id, hidden, display_message_row_id, last_message_row_id, last_read_message_row_id, last_read_receipt_sent_message_row_id, last_important_message_row_id, archived, sort_timestamp, mod_tag, spam_detection, unseen_earliest_message_received_time, unseen_message_count, unseen_missed_calls_count, unseen_row_count, plaintext_disabled, vcard_ui_dismissed, change_number_notified_message_row_id, show_group_description, ephemeral_expiration, ephemeral_setting_timestamp, unseen_important_message_count, ephemeral_disappearing_messages_initiator, group_type, last_message_reaction_row_id, last_seen_message_reaction_row_id, unseen_message_reaction_count, last_read_message_sort_id, display_message_sort_id, last_message_sort_id, last_read_receipt_sent_message_sort_id) values (${elJid}, 0, ${lastMsgId}, ${lastMsgId}, ${lastMsgId}, ${(lastMsgId-1)}, 1, 0, ${DateTime.Now}, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ${lastMsgId}, ${lastMsgId}, ${lastMsgId}, ${(lastMsgId-1)})';"$, "insertChat") ' Log("Insertamos en CHAT") End If 'Obtenemos el id del ultimo mensaje ' Private suCmd1 As String = $"sqlite3 /data/data/com.whatsapp/databases/msgstore.db 'SELECT max(_id) FROM messages';"$ ' Dim nextId As Int = hazRootQuery(suCmd1, "GetId") ' Log("Last ID="&nextId) ' 'Insertamos un boton ' Private suCmd As String = $"sqlite3 /data/data/com.whatsapp/databases/msgstore.db 'INSERT INTO message_template_button (message_row_id, text_data, extra_data, button_type, used) VALUES ("${nextId}", "Boton de Prueba", "Boton de prueba", 0, 1)';"$ ' hazRootQuery(suCmd, "guardaBoton") Private suCmd As String = $"killall com.whatsapp"$ Runner = File.Combine(File.DirInternalCache, "runner") Command = File.Combine(File.DirInternalCache, "command") File.WriteString(File.DirInternalCache, "runner", "su < " & Command) File.WriteString(File.DirInternalCache, "command", suCmd & CRLF & "exit") 'Any commands via crlf, and exit at end Result = Ph.Shell("sh", Array As String(Runner), StdOut, StdErr) If Starter.logger Then Log("Kill WA result : " & Result) If Starter.logger Then LogColor(StdOut.tostring, Colors.red) ' hazRootQuery("killall com.whatsapp", "Kill_WA") End Sub 'Manda un mensaje con imagen al número especificado (52155XXXXXXXX) mediante un script de shell y root. 'El celular necesita estar rooteado. Sub mandaWAImageRoot_0(m As String) 'ignore Starter.waDb.Initialize("/sdcard/", "msgstore_no_enviado.db", True) Dim waPackage, Command, Runner As String Dim StdOut, StdErr, StdOut2, StdErr2 As StringBuilder StdOut.Initialize StdErr.Initialize StdOut2.Initialize StdErr2.Initialize waPackage = Starter.waPackage Dim Result As Int Dim Ph As Phone ' Private suCmd As String = $"sqlite3 /data/data/com.whatsapp/databases/msgstore.db 'SELECT _id, key_remote_jid, data FROM messages WHERE data like "Test%"';"$ Private jid As String = "5215554192439@s.whatsapp.net" Private key_id As String = $"${DateTime.Now}-1"$ Private timeStamp As Int = DateTime.Now ' Private mensaje As String = $"/msjTest ${m} ${DateTime.Time(DateTime.Now)}"$ ' Private received_timestamp As String = "0" Private keyId As String = "" If Starter.logger Then Log(key_id) Private suCmd3 As String = $"killall ${waPackage}"$ Runner = File.Combine(File.DirInternalCache, "runner") Command = File.Combine(File.DirInternalCache, "command") File.WriteString(File.DirInternalCache, "runner", "su < " & Command) File.WriteString(File.DirInternalCache, "command", suCmd3 & CRLF & "exit") 'Any commands via crlf, and exit at end Result = Ph.Shell("sh", Array As String(Runner), StdOut2, StdErr2) If Starter.logger Then Log(Result) If Result = 0 Then Log("process killed") If Starter.logger Then LogColor(StdOut2.tostring, Colors.red) If Starter.logger Then Log(StdOut2) If Starter.logger Then LogColor(StdErr2, Colors.Magenta) Private suCmd1 As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'Select chat._id as chatId FROM chat JOIN jid ON jid._id = chat.jid_row_id where jid.raw_string = "5215554192439@s.whatsapp.net" limit 1';"$ Private chatId As String = hazRootQuery(suCmd1, "getChatId") Private mediaCaption As String = "Alo Papagena … Tore bella com la papaia" ' suCmd1 = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'Select messages.* from messages join message_media on messages._id = message_media.message_row_id order by _id desc limit 1';"$ ' Log(hazRootQuery(suCmd1, "GetMsj")) Dim c As Cursor = Starter.waDb.ExecQuery("Select messages.* from messages join message_media on messages._id = message_media.message_row_id order by _id desc limit 1") 'El ultimo mensaje que tenga imagen If c.RowCount > 0 Then c.Position = 0 keyId = c.GetString("key_id") Private suCmd1 As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'INSERT INTO messages (key_remote_jid, key_from_me, key_id, status, needs_push, timestamp, media_wa_type, media_size, media_name, media_caption, media_hash, media_duration,origin, latitude, longitude, received_timestamp, send_timestamp, receipt_server_timestamp, receipt_device_timestamp, recipient_count, quoted_row_id, edit_version, media_enc_hash, forwarded, preview_type, lookup_tables, future_message_type, message_add_on_flags) VALUES ("${jid}", ${c.GetInt("key_from_me")}, "${key_id}", 0, ${c.GetInt("needs_push")}, ${timeStamp}, "${c.GetString("media_wa_type")}", ${c.GetInt("media_size")}, "${c.GetString("media_name")}", "${mediaCaption}", "${c.GetString("media_hash")}", ${c.GetInt("media_duration")}, ${c.GetInt("origin")}, ${c.GetDouble("latitude")}, ${c.GetDouble("longitude")}, ${c.GetInt("received_timestamp")}, ${c.GetInt("send_timestamp")}, -1, -1, ${c.GetInt("recipient_count")}, ${c.GetInt("quoted_row_id")}, ${c.GetInt("edit_version")}, "${c.GetString("media_enc_hash")}", ${c.GetInt("forwarded")}, ${c.GetInt("preview_type")}, ${c.GetInt("lookup_tables")}, ${c.GetInt("future_message_type")}, ${c.GetInt("message_add_on_flags")})';"$ hazRootQuery(suCmd1, "Messages") 'Insertamos los datos en la tabla "messages". Private msgId As Int = c.GetInt("_id") End If c.Close Private suCmd1 As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'SELECT max(_id) FROM messages';"$ Dim nextId As Int = hazRootQuery(suCmd1, "GetId") Dim c As Cursor = Starter.waDb.ExecQuery($"select * from message_media where message_row_id = '${msgId}'"$) If c.RowCount > 0 Then c.Position = 0 Private filePath As String = c.GetString("file_path") Private suCmd2 As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'insert into message_media (message_row_id, chat_row_id, autotransfer_retry_enabled, media_job_uuid, transferred, transcoded, file_path, file_size, suspicious_content, trim_from, trim_to, face_x, face_y, media_key_timestamp, width, height, has_streaming_sidecar, gif_attribution, thumbnail_height_width_ratio, first_scan_length, file_length, media_name, file_hash, media_duration, page_count, enc_file_hash, is_animated_sticker, mute_video) values (${nextId}, ${chatId}, 1, "${c.getString("media_job_uuid")}", 0, ${c.getInt("transcoded")}, "${filePath}", ${c.getInt("file_size")}, ${c.getInt("suspicious_content")}, ${c.getInt("trim_from")}, ${c.getInt("trim_to")}, ${c.getInt("face_x")}, ${c.getInt("face_y")}, ${c.getInt("media_key_timestamp")}, ${c.getInt("width")}, ${c.getInt("height")}, ${c.getInt("has_streaming_sidecar")}, ${c.getInt("gif_attribution")}, ${c.GetDouble("thumbnail_height_width_ratio")}, ${c.getInt("first_scan_length")}, ${c.getInt("file_length")}, "${c.getString("media_name")}", "${c.getString("file_hash")}", ${c.getInt("media_duration")}, ${c.getInt("page_count")}, "${c.getString("enc_file_hash")}", ${c.getInt("is_animated_sticker")}, ${c.getInt("mute_video")})';"$ If Starter.logger Then Log(hazRootQuery(suCmd2, "MsgMedia")) ' If Result = 0 Then Log("inserted --> message_media") End If c.Close ' Log($"readfile(${filePath}), ${timeStamp}, ${jid}, 1, ${keyId}"$) Private suCmd2 As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'insert into message_thumbnails (thumbnail, timestamp, key_remote_jid, key_from_me, key_id) values (readfile("${filePath}"), ${timeStamp}, "${jid}", 1, "${key_id}")';"$ If Starter.logger Then Log(hazRootQuery(suCmd2, "msgThumbnails")) End Sub Sub hazRootQuery(qryStr As String, name As String) As StringBuilder ' Starter.waDb.Initialize("/sdcard/", "msgstore_no_enviado.db", True) Dim Command, Runner As String Dim StdOut, StdErr As StringBuilder StdOut.Initialize StdErr.Initialize Dim Result As Int Dim Ph As Phone Runner = File.Combine(File.DirInternalCache, "runner") Command = File.Combine(File.DirInternalCache, "command") File.WriteString(File.DirInternalCache, "runner", "su < " & Command) File.WriteString(File.DirInternalCache, "command", qryStr & CRLF & "exit") 'Any commands via crlf, and exit at end Result = Ph.Shell("sh", Array As String(Runner), StdOut, StdErr) ' Log(name&" "&"Res="&Result) ' Log(StdOut) If Starter.logger Then LogColor(StdErr, Colors.red) If StdErr.Length > 1 Then LogColor(qryStr, Colors.Blue) Return StdOut End Sub Sub copyWADB 'ignore Dim waPackage, Command, Runner As String Dim StdOut, StdErr As StringBuilder StdOut.Initialize StdErr.Initialize waPackage = Starter.waPackage Dim Result As Int Dim Ph As Phone Private suCmd3 As String = $"killall ${waPackage}"$ Runner = File.Combine(File.DirInternalCache, "runner") Command = File.Combine(File.DirInternalCache, "command") File.WriteString(File.DirInternalCache, "runner", "su < " & Command) File.WriteString(File.DirInternalCache, "command", suCmd3 & CRLF & "exit") 'Any commands via crlf, and exit at end Result = Ph.Shell("sh", Array As String(Runner), StdOut, StdErr) If Starter.logger Then Log(Result) If Result = 0 Then Log("process killed") If Starter.logger Then LogColor(StdOut.tostring, Colors.red) If Starter.logger Then Log(StdOut) If Starter.logger Then LogColor(StdErr, Colors.Magenta) Private suCmd As String = $"sqlite3 /data/user/0/${waPackage}/databases/msgstore.db 'PRAGMA wal_checkpoint;' cp /data/data/${waPackage}/databases/msgstore.db /sdcard/msgstore.db"$ If Starter.logger Then LogColor(suCmd, Colors.Blue) Runner = File.Combine(File.DirInternalCache, "runner") Command = File.Combine(File.DirInternalCache, "command") File.WriteString(File.DirInternalCache, "runner", "su < " & Command) File.WriteString(File.DirInternalCache, "command", suCmd & CRLF & "exit") 'Any commands via crlf, and exit at end Result = Ph.Shell("sh", Array As String(Runner), StdOut, StdErr) If Starter.logger Then Log(Result) If Starter.logger Then Log(StdOut) If Starter.logger Then LogColor(StdErr, Colors.Magenta) If Result = 0 Then Log("copied db") End Sub 'Regresa una lista de mapas con los datos con los ultimos mensajes con imagen enviados. 'Con este mapa se puede generar un nuevo mensaje con imagen. Sub traeImgMsjData As List Private regs As List regs.Initialize Private sqlSync As String = $"sqlite3 /data/user/0/${Starter.waPackage}/databases/msgstore.db 'PRAGMA wal_checkpoint;'"$ Private sync As String = hazRootQuery(sqlSync, "syncDB") 'Guardamos los datos en la DB 'ignore ' Private suCmd2 As String = $"sqlite3 /data/data/${Starter.waPackage}/databases/msgstore.db 'select * from messages join message_media on message_row_id = _id limit 20';"$ Private suCmd2 As String = $"sqlite3 /data/data/${Starter.waPackage}/databases/msgstore.db 'select _id, key_remote_jid, key_from_me, key_id, status, needs_push, timestamp, media_url, media_mime_type, media_wa_type, media_size, messages.media_name, media_caption, media_hash, messages.media_duration, origin, latitude, longitude, remote_resource, received_timestamp, send_timestamp, receipt_server_timestamp, receipt_device_timestamp, read_device_timestamp, played_device_timestamp, raw_data, recipient_count, participant_hash, starred, quoted_row_id, mentioned_jids, messages.multicast_id, edit_version, media_enc_hash, payment_transaction_id, forwarded, preview_type, send_count, lookup_tables, future_message_type, message_add_on_flags, message_row_id, chat_row_id, autotransfer_retry_enabled, message_media.multicast_id, media_job_uuid, transferred, transcoded, file_path, file_size, suspicious_content, trim_from, trim_to, face_x, face_y, media_key_timestamp, width, height, has_streaming_sidecar, gif_attribution, thumbnail_height_width_ratio, direct_path, first_scan_sidecar, first_scan_length, message_url, mime_type, file_length, message_media.media_name, file_hash, message_media.media_duration, page_count, enc_file_hash, partial_media_hash, partial_media_enc_hash, is_animated_sticker, original_file_hash, mute_video from messages join message_media on message_row_id = _id limit 20';"$ Private tempData As String = hazRootQuery(suCmd2, "traeImgMsjData").As(StringBuilder).ToString Private renglon() As String = Regex.Split(CRLF, tempData) ' Log("======= _"&renglon.Length&"_|"&tempData) For i = 0 To renglon.Length -1 ' LogColor($"i=${i}, ${renglon(i)}"$, Colors.Blue) Private columna() As String = Regex.Split("\|", renglon(i)) ' For col = 0 To columna.Length - 1 ' Log($"col=${col}, ${columna(col)}"$) ' Next If columna.Length > 47 Then Private theDir As String = Starter.waDir & "/" &columna(48) ' Log(theDir) If theDir.EndsWith("jpg") Or theDir.EndsWith("png") Then If File.Exists(theDir.SubString2(0, theDir.LastIndexOf("/")+1), theDir.SubString(theDir.LastIndexOf("/")+1)) Then Private msjData As Map = CreateMap("_id":columna(0), "key_remote_jid":columna(1), "key_from_me":columna(2), "key_id":columna(3), "status":columna(4), "needs_push":columna(5), "timestamp":columna(6), "media_url":columna(7), "media_mime_type":columna(8), "media_wa_type":columna(9), "media_size":columna(10), "media_name":columna(11), "media_caption":columna(12), "media_hash":columna(13), "media_duration":columna(14), "origin":columna(15), "latitude":columna(16), "longitude":columna(17), "remote_resource":columna(18), "received_timestamp":columna(19), "send_timestamp":columna(20), "receipt_server_timestamp":columna(21), "receipt_device_timestamp":columna(22), "read_device_timestamp":columna(23), "played_device_timestamp":columna(24), "raw_data":columna(25), "recipient_count":columna(26), "participant_hash":columna(27), "starred":columna(28), "quoted_row_id":columna(29), "mentioned_jids":columna(30), "multicast_id":columna(31), "edit_version":columna(32), "media_enc_hash":columna(33), "payment_transaction_id":columna(34), "forwarded":columna(35), "preview_type":columna(36), "send_count":columna(37), "lookup_tables":columna(38), "future_message_type":columna(39), "message_add_on_flags":columna(40)) Private imgData As Map = CreateMap("message_row_id":columna(41), "chat_row_id":columna(42), "autotransfer_retry_enabled":columna(43), "multicast_id":columna(44), "media_job_uuid":columna(45), "transferred":columna(46), "transcoded":columna(47), "file_path":columna(48), "file_size":columna(49), "suspicious_content":columna(50), "trim_from":columna(51), "trim_to":columna(52), "face_x":columna(53), "face_y":columna(54), "media_key_timestamp":columna(55), "width":columna(56), "height":columna(57), "has_streaming_sidecar":columna(58), "gif_attribution":columna(59), "thumbnail_height_width_ratio":columna(60), "direct_path":columna(61), "first_scan_sidecar":columna(62), "first_scan_length":columna(63), "message_url":columna(64), "mime_type":columna(65), "file_length":columna(66), "media_name":columna(67), "file_hash":columna(68), "media_duration":columna(69), "page_count":columna(70), "enc_file_hash":columna(71), "partial_media_hash":columna(72), "partial_media_enc_hash":columna(73), "is_animated_sticker":columna(74), "original_file_hash":columna(75), "mute_video":columna(76)) Private thisReg As Map = CreateMap("msjData":msjData, "imgData":imgData) ' LogColor("Agregamos registro "& i, Colors.Magenta) regs.Add(thisReg) End If End If End If Next ' Log(regs) ' Log("Registros="®s.Size) ' For x = 0 To regs.Size-1 ' Log(regs.Get(x)) ' Next Return regs End Sub 'Manda un mensaje con imagen al número especificado (52155XXXXXXXX) mediante un script de shell y root. 'El celular necesita estar rooteado. Sub mandaWAImageRoot(jid As String, texto As String, msjMap As Map) 'ignore Starter.waDb.Initialize("/sdcard/", "msgstore_no_enviado.db", True) jid = "5215554192439@s.whatsapp.net" Private mediaCaption As String = "Alo Papagena … Tore bella com la papaia" Private filePath As String = "/storage/F3DF-3FB8/Bow2.0/qr.jpg" If texto <> "" And texto <> Null Then mediaCaption = texto Dim waPackage As String = Starter.waPackage Private key_id As String = $"${DateTime.Now}-1"$ Private timeStamp As String = DateTime.Now Private keyId As String = "" If Starter.logger Then Log($"jid=${jid}, timeStamp=${timeStamp}, key_Id=${key_id}, now=${DateTime.Now}"$) If Starter.logger Then LogColor(msjMap, Colors.Blue) '============================== Kill Process ============================== Private killWA As String = hazRootQuery($"killall ${waPackage}"$, "killWA") 'Matamos el proceso de WA 'ignore '============================================================ Private sqlGetChatId As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'Select chat._id as chatId FROM chat JOIN jid ON jid._id = chat.jid_row_id where jid.raw_string = "${jid}" limit 1';"$ Private chatId As String = hazRootQuery(sqlGetChatId, "getChatId") 'Obtenenos el ID del chat del JID proporcionado. ' Dim c As Cursor = Starter.waDb.ExecQuery("Select messages.* from messages join message_media on messages._id = message_media.message_row_id order by _id desc limit 1") 'El ultimo mensaje que tenga imagen ' If c.RowCount > 0 Then ' c.Position = 0 '=============================== Insert into Messages ============================== Private msjInfo As Map = msjMap.Get("msjData") keyId = msjInfo.Get("key_id") Private sqlInsertMsg As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'INSERT INTO messages (key_remote_jid, key_from_me, key_id, status, needs_push, timestamp, media_wa_type, media_size, media_name, media_caption, media_hash, media_duration, origin, latitude, longitude, received_timestamp, send_timestamp, receipt_server_timestamp, receipt_device_timestamp, recipient_count, quoted_row_id, edit_version, media_enc_hash, forwarded, preview_type, lookup_tables, future_message_type, message_add_on_flags) VALUES ("${jid}", ${msjInfo.Get("key_from_me")}, "${key_id}", 0, ${msjInfo.Get("needs_push")}, ${timeStamp}, "${msjInfo.Get("media_wa_type")}", ${msjInfo.Get("media_size")}, "${msjInfo.Get("media_name")}", "${mediaCaption}", "${msjInfo.Get("media_hash")}", ${msjInfo.Get("media_duration")}, ${msjInfo.Get("origin")}, ${msjInfo.Get("latitude")}, ${msjInfo.Get("longitude")}, ${msjInfo.Get("received_timestamp")}, ${msjInfo.Get("send_timestamp")}, -1, -1, ${msjInfo.Get("recipient_count")}, ${msjInfo.Get("quoted_row_id")}, ${msjInfo.Get("edit_version")}, "${msjInfo.Get("media_enc_hash")}", ${msjInfo.Get("forwarded")}, ${msjInfo.Get("preview_type")}, ${msjInfo.Get("lookup_tables")}, ${msjInfo.Get("future_message_type")}, ${msjInfo.Get("message_add_on_flags")})';"$ If Starter.logger Then LogColor(sqlInsertMsg, Colors.Magenta) hazRootQuery(sqlInsertMsg, "InsertMessage") 'Insertamos los datos en la tabla "messages". ' Private msgId As Int = msjInfo.Get("_id") ' End If ' c.Close '=============================== Get last Id ============================= Private sqlGetLastMsgId As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'SELECT max(_id) FROM messages';"$ Dim nextId As Int = hazRootQuery(sqlGetLastMsgId, "GetLastId") Starter.reglasDB.ExecNonQuery($"INSERT INTO datosMsj (_id, key_remote_jid, key_from_me, key_id, status, needs_push, timestamp, media_wa_type, media_size, media_name, media_caption, media_hash, media_duration, origin, latitude, longitude, received_timestamp, send_timestamp, receipt_server_timestamp, receipt_device_timestamp, recipient_count, quoted_row_id, edit_version, media_enc_hash, forwarded, preview_type, lookup_tables, future_message_type, message_add_on_flags) VALUES ("${nextId}", "${jid}", ${msjInfo.Get("key_from_me")}, "${key_id}", 0, ${msjInfo.Get("needs_push")}, ${timeStamp}, "${msjInfo.Get("media_wa_type")}", ${msjInfo.Get("media_size")}, "${msjInfo.Get("media_name")}", "${mediaCaption}", "${msjInfo.Get("media_hash")}", ${msjInfo.Get("media_duration")}, ${msjInfo.Get("origin")}, ${msjInfo.Get("latitude")}, ${msjInfo.Get("longitude")}, ${msjInfo.Get("received_timestamp")}, ${msjInfo.Get("send_timestamp")}, -1, -1, ${msjInfo.Get("recipient_count")}, ${msjInfo.Get("quoted_row_id")}, ${msjInfo.Get("edit_version")}, "${msjInfo.Get("media_enc_hash")}", ${msjInfo.Get("forwarded")}, ${msjInfo.Get("preview_type")}, ${msjInfo.Get("lookup_tables")}, ${msjInfo.Get("future_message_type")}, ${msjInfo.Get("message_add_on_flags")})"$) ' Dim c As Cursor = Starter.waDb.ExecQuery($"select * from message_media where message_row_id = '${msgId}'"$) ' If c.RowCount > 0 Then ' c.Position = 0 '=============================== Insert into message_media ============================ Private imgInfo As Map = msjMap.Get("imgData") Private theDir As String = Starter.waDir & "/" & imgInfo.get("file_path") If Starter.logger Then Log("file_path="&imgInfo.get("file_path")) If Starter.logger Then Log($"ImgDir=${theDir}"$) If File.Exists(theDir.SubString2(0, theDir.LastIndexOf("/")+1), theDir.SubString(theDir.LastIndexOf("/")+1)) Then File.Copy(theDir.SubString2(0, theDir.LastIndexOf("/")+1), theDir.SubString(theDir.LastIndexOf("/")+1), "/sdcard/Bow2.0/", theDir.SubString(theDir.LastIndexOf("/")+1)) filePath = "/sdcard/Bow2.0/" & theDir.SubString(theDir.LastIndexOf("/")+1) End If If Starter.logger Then LogColor($"filePath=${filePath}"$, Colors.Magenta) Private sqlInsertMedia As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'insert into message_media (message_row_id, chat_row_id, autotransfer_retry_enabled, media_job_uuid, transferred, transcoded, file_path, file_size, suspicious_content, trim_from, trim_to, face_x, face_y, media_key_timestamp, width, height, has_streaming_sidecar, gif_attribution, thumbnail_height_width_ratio, first_scan_length, file_length, media_name, file_hash, media_duration, page_count, enc_file_hash, is_animated_sticker, mute_video) values (${nextId}, ${chatId}, 1, "abcd${imgInfo.get("media_job_uuid").As(String).SubString(4)}", 0, ${imgInfo.get("transcoded")}, "${filePath}", ${imgInfo.get("file_size")}, ${imgInfo.get("suspicious_content")}, ${imgInfo.get("trim_from")}, ${imgInfo.get("trim_to")}, ${imgInfo.get("face_x")}, ${imgInfo.get("face_y")}, ${imgInfo.get("media_key_timestamp")}, ${imgInfo.get("width")}, ${imgInfo.get("height")}, ${imgInfo.get("has_streaming_sidecar")}, ${imgInfo.get("gif_attribution")}, ${imgInfo.get("thumbnail_height_width_ratio")}, ${imgInfo.get("first_scan_length")}, ${imgInfo.get("file_length")}, "${imgInfo.get("media_name")}", "${imgInfo.get("file_hash")}", ${imgInfo.get("media_duration")}, ${imgInfo.get("page_count")}, "${imgInfo.get("enc_file_hash")}", ${imgInfo.get("is_animated_sticker")}, ${imgInfo.get("mute_video")})';"$ If Starter.logger Then LogColor(sqlInsertMedia, Colors.Magenta) If Starter.logger Then Log(hazRootQuery(sqlInsertMedia, "MsgMedia")) Starter.reglasDB.ExecNonQuery($"insert into datosImg (message_row_id, chat_row_id, autotransfer_retry_enabled, media_job_uuid, transferred, transcoded, file_path, file_size, suspicious_content, trim_from, trim_to, face_x, face_y, media_key_timestamp, width, height, has_streaming_sidecar, gif_attribution, thumbnail_height_width_ratio, first_scan_length, file_length, media_name, file_hash, media_duration, page_count, enc_file_hash, is_animated_sticker, mute_video) values (${nextId}, ${chatId}, 1, "abcd${imgInfo.get("media_job_uuid").As(String).SubString(4)}", 0, ${imgInfo.get("transcoded")}, "${filePath}", ${imgInfo.get("file_size")}, ${imgInfo.get("suspicious_content")}, ${imgInfo.get("trim_from")}, ${imgInfo.get("trim_to")}, ${imgInfo.get("face_x")}, ${imgInfo.get("face_y")}, ${imgInfo.get("media_key_timestamp")}, ${imgInfo.get("width")}, ${imgInfo.get("height")}, ${imgInfo.get("has_streaming_sidecar")}, ${imgInfo.get("gif_attribution")}, ${imgInfo.get("thumbnail_height_width_ratio")}, ${imgInfo.get("first_scan_length")}, ${imgInfo.get("file_length")}, "${imgInfo.get("media_name")}", "${imgInfo.get("file_hash")}", ${imgInfo.get("media_duration")}, ${imgInfo.get("page_count")}, "${imgInfo.get("enc_file_hash")}", ${imgInfo.get("is_animated_sticker")}, ${imgInfo.get("mute_video")})"$) ' If Result = 0 Then Log("inserted --> message_media") ' End If ' c.Close '=============================== Insert into message_thumbnails ============================ Private sqlInsertThumb As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'insert into message_thumbnails (thumbnail, timestamp, key_remote_jid, key_from_me, key_id) values (readfile("${filePath}"), ${timeStamp}, "${jid}", 1, "${key_id}")';"$ If Starter.logger Then LogColor(sqlInsertThumb, Colors.Magenta) If Starter.logger Then Log(hazRootQuery(sqlInsertThumb, "msgThumbnails")) End Sub